home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume25 / ile < prev    next >
Encoding:
Internet Message Format  |  1991-12-13  |  82.0 KB

  1. Subject: v25i029: ile - an input line editor
  2. Newsgroups: comp.sources.unix
  3. Approved: vixie@pa.dec.com
  4.  
  5. Submitted-By: Robert C. Pendleton <bobp@hal.com>
  6. Posting-Number: Volume 25, Issue 29
  7. Archive-Name: ile
  8.  
  9. [ This program gives you interactive line editing similar to tcsh or ksh,
  10.   except that it will run any program as its subprocess, so although you
  11.   don't get to carry the `history' context from program to program, you
  12.   can get fancy editing in programs that don't neccessarily support it.
  13.   Running "ile /bin/csh" is a lot like tcsh, and "ile /bin/sh" is a lot
  14.   like ksh.  I wrote the Makefile.                                 --vix ]
  15.  
  16. #! /bin/sh
  17. # This is a shell archive.  Remove anything before this line, then unpack
  18. # it by saving it into a file and typing "sh file".  To overwrite existing
  19. # files, type "sh file -c".  You can also feed this as standard input via
  20. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  21. # will see the following message at the end:
  22. #        "End of archive 1 (of 1)."
  23. # Contents:  MANIFEST Makefile README ile.1 ile.c
  24. # Wrapped by vixie@cognition.pa.dec.com on Fri Dec 13 14:38:22 1991
  25. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  26. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  28. else
  29. echo shar: Extracting \"'MANIFEST'\" \(269 characters\)
  30. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  31. X   File Name        Archive #    Description
  32. X-----------------------------------------------------------
  33. X MANIFEST                   1    This shipping list
  34. X Makefile                   1    
  35. X README                     1    
  36. X ile.1                      1    
  37. X ile.c                      1    
  38. END_OF_FILE
  39. if test 269 -ne `wc -c <'MANIFEST'`; then
  40.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  41. fi
  42. # end of 'MANIFEST'
  43. fi
  44. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  45.   echo shar: Will not clobber existing file \"'Makefile'\"
  46. else
  47. echo shar: Extracting \"'Makefile'\" \(223 characters\)
  48. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  49. X# vix 13dec91
  50. X
  51. DESTPATH = /usr/local
  52. CFLAGS = -g
  53. CC = cc
  54. X
  55. all: ile
  56. X
  57. clean:
  58. X    -rm *.o
  59. X    -rm ile
  60. X
  61. install:
  62. X    install -c ile $(DESTPATH)/bin/ile
  63. X    install -c ile.1 $(DESTPATH)/man/man1/ile.1
  64. X
  65. ile: ile.o
  66. X    cc -o ile ile.o -ltermcap
  67. END_OF_FILE
  68. if test 223 -ne `wc -c <'Makefile'`; then
  69.     echo shar: \"'Makefile'\" unpacked with wrong size!
  70. fi
  71. # end of 'Makefile'
  72. fi
  73. if test -f 'README' -a "${1}" != "-c" ; then 
  74.   echo shar: Will not clobber existing file \"'README'\"
  75. else
  76. echo shar: Extracting \"'README'\" \(250 characters\)
  77. sed "s/^X//" >'README' <<'END_OF_FILE'
  78. NAME
  79. X     ile - An input line editor for UNIX (Input Line Editor)
  80. X
  81. SYNTAX
  82. X     ile [-file/name] [prog arg1 arg2 ... argn]
  83. X
  84. DESCRIPTION
  85. X     The ile program is an input line editor that provides an
  86. X     easier to use history mechanism than the shell.
  87. END_OF_FILE
  88. if test 250 -ne `wc -c <'README'`; then
  89.     echo shar: \"'README'\" unpacked with wrong size!
  90. fi
  91. # end of 'README'
  92. fi
  93. if test -f 'ile.1' -a "${1}" != "-c" ; then 
  94.   echo shar: Will not clobber existing file \"'ile.1'\"
  95. else
  96. echo shar: Extracting \"'ile.1'\" \(16441 characters\)
  97. sed "s/^X//" >'ile.1' <<'END_OF_FILE'
  98. X.de EX        \"Begin example
  99. X.ne 5
  100. X.if n .sp 1
  101. X.if t .sp .5
  102. X.nf
  103. X.in +.5i
  104. X..
  105. X.de EE
  106. X.fi
  107. X.in -.5i
  108. X.if n .sp 1
  109. X.if t .sp .5
  110. X..
  111. X.TH ILE 1 "5 May 1988" 
  112. X.SH NAME
  113. X.PP
  114. ile - An input line editor for UNIX (Input Line Editor)
  115. X.PP
  116. X.SH SYNTAX
  117. X.PP
  118. X\fBile\fP [-file/name\fP] \fP[prog arg1 arg2 ... argn\fP]
  119. X.PP
  120. X.SH DESCRIPTION
  121. X.PP
  122. X
  123. The \fIile\fP program is an input line editor that provides an easier
  124. to use history mechanism than the shell.
  125. X
  126. X.PP
  127. X
  128. The \fIile\fP program can be run as a simple shell around any program.
  129. It gives any program an input line editing and a history mechanism. It
  130. can also be run around your favorite shell. When run around the shell
  131. X\fIile\fP records the input to programs as well as input to the shell
  132. in its history buffer.
  133. X
  134. X\fIile\fP takes two optional command line arguments. The first
  135. argument is the name of an initialization file containing user defined
  136. key and delimiter bindings. The second argument is the name of a
  137. program to execute and the command line arguments for that program.
  138. X
  139. X.PP
  140. X
  141. If no initialization file is given on the command line \fIile\fP first
  142. looks in \fI./.ilerc\fP and then in \fI$HOME/.ilerc\fP. If no
  143. initialization file is found \fIile\fP provides default values for
  144. delimiter and key bindings.
  145. X
  146. X.PP
  147. X
  148. If no program name is given on the command line \fIile\fP executes
  149. X\fIcsh\fp.
  150. X
  151. X.PP
  152. X.SH DEFAULT BINDINGS
  153. X.PP
  154. X
  155. Not everyone wants to have to figure out yet another initialization
  156. file format so \fIile\fP provides a complete set of default bindings
  157. for all its operations.
  158. X
  159. X.PP
  160. X.SH Delimiters
  161. X.PP
  162. X
  163. Delimiters are used in \fIile\fP to mark the beginnings and ends of
  164. words for the \fBforward_word\fP, \fBbackward_word\fP, and
  165. X\fBdelete_word\fP actions. The default delimiters are ' ' (blank), '/'
  166. X(slash), '.' (period), and '-' (dash). These were chosen because the
  167. author decided they were "natural" stopping characters in a UNIX
  168. environment.
  169. X
  170. X.PP
  171. X.SH Keys
  172. X.PP
  173. X
  174. The following table shows the default bindings of keys and key
  175. sequences provided by \fIile\fP. These are based on the emacs key
  176. bindings for similar operations.
  177. X
  178. X.EX 0
  179. X
  180. X^A      - start_of_line
  181. X^B      - backward_char
  182. X^E      - end_of_line
  183. X^F      - forward_char
  184. X^K      - erase_to_end_of_line
  185. X^L      - retype_line
  186. X^N      - forward_history
  187. X^P      - backward_history
  188. X^R      - search_backward_history
  189. X^V      - quote
  190. X^T      - transpose_chars
  191. del     - delete_char
  192. X^M      - add_to_history
  193. X^J      - add_to_history
  194. X^U      - erase_line
  195. X^X      - delete_char_under
  196. X
  197. X^C      - pass
  198. X^D      - pass
  199. X^Q      - pass
  200. X^S      - pass
  201. X^Z      - pass
  202. X
  203. esc b   - backward_word
  204. esc f   - forward_word
  205. esc del - delete_word
  206. esc esc - complete_file
  207. esc s   - complete_file_full
  208. esc p   - query_path
  209. esc d   - show_files
  210. esc u   - upper_word
  211. esc l   - lower_word
  212. esc c   - capitalize_word
  213. X
  214. esc [ A - backward_history (up arrow)
  215. esc [ B - forward_history  (down arrow)
  216. esc [ C - forward_char     (right arrow)
  217. esc [ D - backward_char    (left arrow)
  218. X.EE
  219. X
  220. X.SH INITIALIZATION FILE
  221. X.PP
  222. X
  223. The \fIile\fP initialization file has two parts. The first part is
  224. also the first line of the file. This line contains the delimiter
  225. characters that will be used by the \fBforward_word\fP,
  226. X\fBbackward_word\fP, and \fBdelete_word\fP actions.  Each character on
  227. the line becomes a delimiter character.
  228. X
  229. The second part of the file is a list of table numbers, characters,
  230. and actions or strings. \fIile\fP has 4 action tables. Each action
  231. table contains an action or string for each possible character.
  232. X\fIile\fP decides what to do with a character by looking it up in the
  233. table and executing the action associated with the character or by
  234. passing the string one character at a time into \fIile\fP as if it had
  235. been typed by the user. Normally only table 0 is used. But, the
  236. X\fBescape\fP actions cause the next character to be looked up in a
  237. different table. The \fBescape\fP actions make it possible to map
  238. multiple character sequences to actions.
  239. X
  240. By default, all entries in table 0 are bound to the \fBinsert\fP
  241. action, and all entries in the other tables are bound to the
  242. X\fBbell\fP action. User specified bindings override these defaults.
  243. The following example is an initialization file that sets up the same
  244. key and delimiter bindings as the \fIile\fP default bindings.
  245. X
  246. X.PP
  247. X.SH Example \fI.ilerc\fP file
  248. X.EX 0
  249. X /.-
  250. X
  251. X0^A=start_of_line
  252. X0^B=backward_char
  253. X0^E=end_of_line
  254. X0^F=forward_char
  255. X0^K=erase_to_end_of_line
  256. X0^L=retype_line
  257. X0^N=forward_history
  258. X0^P=backward_history
  259. X0^R=search_backward_history
  260. X0^V=quote
  261. X0^T=transpose_chars
  262. X0\\177=delete_char
  263. X0^[=escape_1
  264. X0^M=add_to_history
  265. X0^J=add_to_history
  266. X0^U=erase_line
  267. X0^X=delete_char_under
  268. X
  269. X0^C=pass
  270. X0^D=pass
  271. X0^Q=pass
  272. X0^S=pass
  273. X0^Z=pass
  274. X
  275. X1b=backward_word
  276. X1f=forward_word
  277. X1\\177=delete_word
  278. X1[=escape_2
  279. X1^[=complete_file
  280. X1s=complete_file_full
  281. X1p=query_path
  282. X1d=show_files
  283. X1u=upper_word
  284. X1l=lower_word
  285. X1c=capitalize_word
  286. X
  287. X2A=backward_history
  288. X2B=forward_history
  289. X2C=forward_char
  290. X2D=backward_char
  291. X.EE
  292. X
  293. X.PP
  294. X
  295. The first character on each key binding line is the index of the table
  296. to place the key binding in. Valid values for the index are 0, 1, 2,
  297. and 3.
  298. X
  299. X.PP
  300. X
  301. The second character on the line is either the character to bind or an
  302. indicator that tells how to find out what character to bind. If the
  303. second character is any character besides '^' or '\\' then the action
  304. is bound to that character.
  305. X
  306. X.PP
  307. X
  308. If the second character on the line is '^' then the next character is
  309. taken as the name of a control character. So ^H is backspace and ^[ is
  310. escape.
  311. X
  312. X.PP
  313. X
  314. If the second character on the line is a '\\' and the next character
  315. is a digit between 0 and 7 the the following characters are
  316. interpreted as an octal number that indicates which character to bind
  317. the action to. If the character immediately after the '\\' is not an
  318. octal digit then the action is bound to that character. For example,
  319. to get the '^' character you would use '\\^'.
  320. X
  321. X.PP
  322. X
  323. The next character on the line is always '='. Following the equal sign
  324. is the name of an action or a string. The actions are defined in the
  325. following table.
  326. X
  327. X.PP
  328. X.SH Actions
  329. X
  330. X.IP "\fBbell\fP" 20
  331. X
  332. Send a bell (^G) character to the terminal.  Hopefully the bell will
  333. ring.  This action is a nice way to tell the user that an invalid
  334. sequence of keys has been typed.
  335. X
  336. X.IP "\fBpass\fP" 20 
  337. X
  338. Pass the character to the program running under \fIile\fP. Do not echo
  339. the character, do not insert it into the edit buffer. Just pass it
  340. along.  This is useful for characters like ^C, ^Z, ^Q, and ^S that
  341. have special meaning and shouldn't be held up in the edit buffer
  342. waiting to be sent.
  343. X
  344. X.IP "\fBinsert\fP" 20 
  345. X
  346. Insert the character into the edit buffer. If there are already 256
  347. characters in the buffer \fIile\fP will beep and refuse to put the
  348. character in the buffer.
  349. X
  350. X.IP "\fBtranspose_chars\fP" 20
  351. X
  352. Swap the character under the cursor with the character to the left of
  353. the cursor and move the cursor one character to the right. This is
  354. handy for correcting letter transposition errors.  
  355. X
  356. X.IP "\fBdelete_char\fP" 20
  357. X
  358. X Delete the character directly to the left of the cursor from the edit
  359. buffer.
  360. X
  361. X.IP "\fBdelete_char_under\fP" 20
  362. Delete the character under the cursor from the edit buffer.
  363. X
  364. X.IP "\fBquote\fP" 20
  365. The next character to come into \fIile\fP will be inserted into the edit
  366. buffer. This allows you to put characters into the edit buffer
  367. that are bound to an action other than insert.
  368. X
  369. X.IP "\fBescape_1\fP" 20
  370. Look up the next character in action table 1 instead of action table 0.
  371. X
  372. X.IP "\fBescape_2\fP" 20
  373. Look up the next character in action table 2 instead of action table 0.
  374. X
  375. X.IP "\fBescape_3\fP" 20
  376. Look up the next character in action table 3 instead of action table 0.
  377. X
  378. X.IP "\fBdelete_word\fP" 20
  379. Delete the word directly to the left of the cursor. A word is a sequence
  380. of characters surrounded by delimiter characters.
  381. X
  382. X.IP "\fBforward_word\fP" 20
  383. Move the cursor to the right past the next word. A word is a sequence of
  384. characters surrounded by delimiter characters.
  385. X
  386. X.IP "\fBbackward_word\fP" 20
  387. Move the cursor to the left past the next word. A word is a sequence of
  388. characters surrounded by delimiter characters.
  389. X
  390. X.IP "\fBupper_word\fP" 20
  391. X
  392. Starting with the character under the cursor, convert the word to the 
  393. right of the cursor to upper case.
  394. X
  395. X.IP "\fBlower_word\fP" 20
  396. X
  397. Starting with the character under the cursor, convert the word to the
  398. right of the cursor to lower case.
  399. X
  400. X.IP "\fBcapitalize_word\fP" 20
  401. X
  402. Convert the character under the cursor to upper case. Convert the word to
  403. the right of the cursor to lower case.
  404. X
  405. X.IP "\fBstart_of_line\fP" 20
  406. Move the cursor to the left most character in the edit buffer.
  407. X
  408. X.IP "\fBbackward_char\fP" 20
  409. Move the cursor to the left one character.
  410. X
  411. X.IP "\fBend_of_line\fP" 20
  412. Move the cursor past the last character in the edit buffer.
  413. X
  414. X.IP "\fBforward_char\fP" 20
  415. Move the cursor to the right one character.
  416. X
  417. X.IP "\fBadd_to_history\fP" 20
  418. Add the contents of the edit buffer to the history buffer and pass the line
  419. along to the program running under \fIile\fP.
  420. X
  421. X.IP "\fBerase_line\fP" 20
  422. Clear the line. Erase all characters on the line.
  423. X
  424. X.IP "\fBerase_to_end_of_line\fP" 20
  425. Delete the character under the cursor and all character to the left
  426. of the cursor from the edit buffer.
  427. X
  428. X.IP "\fBretype_line\fP" 20
  429. Retype the contents of the current edit buffer. This is handy when system
  430. messages or other asynchronous output has garbled the input line.
  431. X
  432. X.IP "\fBforward_history\fP" 20
  433. Display the next entry in the history buffer. If you are already at the
  434. most recent entry display a blank line. If you try to go forward past
  435. the blank line this command will beep at you.
  436. X
  437. X.IP "\fBbackward_history\fP" 20
  438. Display the previous entry in the history buffer. If there are no older
  439. entries in the buffer, beep.
  440. X
  441. X.IP "\fBsearch_backward_history\fP" 20 
  442. X
  443. Search for a line in the history buffer that starts with the
  444. characters to the left of the cursor.  If a match is found the matched
  445. line is displayed. If no match is found this command will beep at you.
  446. X
  447. X.IP "\fBcomplete_file\fP" 20
  448. X
  449. Take the word currently under, or immediately to the left of the
  450. cursor and treat it as a partial file name and path name. If there is
  451. only one file in the directory that starts with the partial file name
  452. then fill in the rest of the file name in the input line. If more than
  453. one file starts with the partial file name fill in the longest common
  454. starting string of those file names.  If the path is specified as "~/"
  455. then look in the directory named by $HOME.
  456. X
  457. If the path is specified as "~name", where name is a user login name or
  458. a partial user login name, then look in the users login directory. If
  459. more than one match is found for a partial user name then \fIile\fP
  460. will beep. When completing a file name, a partial user name will be
  461. completed at the same time the file name is being completed.
  462. X
  463. If you use abbreviated path names like "./file", "../file",
  464. X"dir/file", or "file" \fIile\fP uses the path name saved by the most
  465. recent \fBquery_path\fP command or the value of $PWD at the time
  466. X\fIile\fp was started.
  467. X
  468. X.IP "\fBcomplete_file_full\fP" 20
  469. X
  470. Like \fBcomplete_file\fP but abbreviations like "~/" are replaced by
  471. the full path that they stand for. This is handy when you want to use
  472. abbreviated path names but the program you are talking to doesn't
  473. understand the abbreviations.
  474. X
  475. Read the discussion of file name completion under \fBcomplete_file\fP
  476. for more information.
  477. X
  478. X.IP "\fBquery_path\fP" 20
  479. X
  480. X\fIile\fP isn't the shell and doesn't know what the current working
  481. directory is. But, \fIile\fP tries to do file name completion as if it
  482. did. To do this task \fIile\fP keeps around the path to the current
  483. working directory. When \fIile\fP is started up this path is
  484. initialized from $PWD. The \fBquery_path\fP command is provided to
  485. allow users to update this path at any time.
  486. X
  487. When \fBquery_path\fP is invoked \fIile\fP makes the blatant
  488. assumption that the program running under \fIile\fP is a shell and
  489. sends the shell command "pwd" to that program. Whatever comes back
  490. from the program is assumed to the path to the current working
  491. directory. The next response from the program is assumed to be a new
  492. prompt from the shell and is ignored.
  493. X
  494. X.IP "\fBshow_files\fP" 20
  495. Take the word currently under, or immediately to the left of, the cursor and 
  496. treat it as a partial file name and path name. List all the files that start
  497. with the partial file name in the directory specified by the path name.
  498. X
  499. Read the discussion of file name completion under \fBcomplete_file\fP
  500. for more information.
  501. X
  502. X.PP
  503. X.SH Strings
  504. X
  505. In addition to being able to bind a character sequence to an action \fIile\fP
  506. allows characters sequences to be bound to strings of characters. When a string
  507. is invoked the characters in the string are treated as if they were typed
  508. by the user. For example, if the line:
  509. X.EX 0
  510. X0^G=ring^Ma^Mbell^M
  511. X.EE
  512. was in your \fI.ilerc\fP file, typing control G would cause three
  513. lines to be typed as if the user typed them. Using the default bindings,
  514. unless there is a ^J or ^M in the string the string will be inserted
  515. in the current line but not sent along until the the user actually
  516. presses return.
  517. X
  518. X.PP
  519. X.SH Error Messages
  520. X.PP
  521. X
  522. When \fIile\fP encounters errors it prints a message and terminates.
  523. X\fIile\fP can print several standard error message. It can also print
  524. a few messages that are specific to \fIile\fP.
  525. X
  526. X.IP "\fBile: unable to allocate pty/tty pair\fP" 20
  527. X
  528. There are no free pty devices in the system. You can either try again later,
  529. and hope someone has freed a pty for you to use, or you can grab your
  530. system manager and try to get more pty devices configured.
  531. X
  532. X.IP "\fBile: '=' missing on line #\fP" 20
  533. X
  534. In a character binding line you left out the '=' character. Or, you did 
  535. something that confused the initialization file reader into thinking there
  536. should be an '=' where you didn't think there should be one.
  537. X
  538. X.IP "\fBile: error in initialization file on line #\fP" 20
  539. X
  540. This means that the first character of a character binding line wasn't
  541. a newline or a '0', '1', '2', or '3'. It could also mean that the 
  542. initialization file reader is confused.
  543. X
  544. X.IP "\fBile: can't find terminal\fP" 20
  545. X
  546. X\fIile\fP could not find a termcap entry for the terminal named by the TERM
  547. environment variable. Since it can't find it \fIile\fP can't figure out
  548. how to use it.
  549. X
  550. X.IP "\fBile: can't run on terminal\fP" 20
  551. X
  552. The terminal named in your TERM environment variable doesn't support
  553. the capabilities \fIile\fP needs to run. So \fIile\fP doesn't even try.
  554. X
  555. X.PP
  556. X.SH BUGS
  557. X.PP
  558. X\fIile\fP changes the input mode on the controlling terminal to RAW. This
  559. confuses xterm. It is a good idea to include the line:
  560. X.EX 0
  561. stty cooked -nl echo tabs crt decctlq -litout
  562. X.EE
  563. in your .cshrc file when using xterm. Otherwise your new xterm windows
  564. come up in an unusable state.
  565. X.PP
  566. X\fIile\fP requires a terminal that supports the termcap le, ce, bl, 
  567. nl, and cr capabilities. If your terminal doesn't provide these,
  568. X\fIile\fP will refuse to run on your terminal.
  569. X.PP
  570. A misspelled action name in an \fIilerc\fP will be treated as a string.
  571. This means that typing the sequence of characters that should
  572. invoke the action will actually cause the misspelled name to be inserted
  573. in the input line. 
  574. X.PP
  575. X.SH FILES
  576. X.PP
  577. X $HOME/.ilerc
  578. X ./.ilerc
  579. X.PP 
  580. X.SH SEE ALSO
  581. X.PP
  582. stty(1), xterm(1), csh(1), termcap(5)
  583. X
  584. X.SH COPYRIGHT
  585. X.ce 4
  586. COPYRIGHT 1988
  587. XEvans & Sutherland Computer Corporation
  588. Salt Lake City, Utah
  589. All Rights Reserved.
  590. X.LP
  591. THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
  592. SHOULD NOT BE CONSTRUED AS A COMMITMENT BY EVANS & SUTHERLAND.
  593. XEVANS & SUTHERLAND  MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY
  594. OF THIS SOFTWARE FOR
  595. ANY PURPOSE.  IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
  596. X.LP
  597. IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT RIGHTS,
  598. APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN ADDITION TO THAT
  599. SET FORTH ABOVE.
  600. X.LP
  601. Permission to use, copy, modify, and distribute this software and its
  602. documentation for any purpose and without fee is hereby granted, provided
  603. that the above copyright notice appear in all copies and that both the
  604. copyright notice and this permission notice appear in supporting documentation,
  605. and that the name of Evans & Sutherland not be used in advertising
  606. or publicity pertaining to distribution of the software without specific, 
  607. written prior permission.
  608. X.SH AUTHOR
  609. Robert C. Pendleton <bobp@hal.com>
  610. X.LP
  611. X
  612. END_OF_FILE
  613. if test 16441 -ne `wc -c <'ile.1'`; then
  614.     echo shar: \"'ile.1'\" unpacked with wrong size!
  615. fi
  616. # end of 'ile.1'
  617. fi
  618. if test -f 'ile.c' -a "${1}" != "-c" ; then 
  619.   echo shar: Will not clobber existing file \"'ile.c'\"
  620. else
  621. echo shar: Extracting \"'ile.c'\" \(60367 characters\)
  622. sed "s/^X//" >'ile.c' <<'END_OF_FILE'
  623. X/*
  624. X                          COPYRIGHT 1988
  625. X              Evans & Sutherland Computer Corporation
  626. X                        Salt Lake City, Utah
  627. X                        All Rights Reserved.
  628. X
  629. X     THE INFORMATION  IN  THIS  SOFTWARE  IS  SUBJECT  TO  CHANGE
  630. X     WITHOUT  NOTICE  AND SHOULD NOT BE CONSTRUED AS A COMMITMENT
  631. X     BY  EVANS  &  SUTHERLAND.   EVANS  &  SUTHERLAND   MAKES  NO
  632. X     REPRESENTATIONS  ABOUT  THE SUITABILITY OF THIS SOFTWARE FOR
  633. X     ANY PURPOSE.  IT IS SUPPLIED  "AS  IS"  WITHOUT  EXPRESS  OR
  634. X     IMPLIED WARRANTY.
  635. X
  636. X     IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING  DERIVATIVE
  637. X     COPYRIGHT  RIGHTS,  APPROPRIATE LEGENDS MAY BE PLACED ON THE
  638. X     DERIVATIVE WORK IN ADDITION TO THAT SET FORTH ABOVE.
  639. X
  640. X     Permission  to  use,  copy,  modify,  and  distribute   this
  641. X     software  and  its documentation for any purpose and without
  642. X     fee is hereby granted, provided  that  the  above  copyright
  643. X     notice  appear  in  all  copies  and that both the copyright
  644. X     notice and this permission notice appear in supporting docu-
  645. X     mentation,  and  that  the name of Evans & Sutherland not be
  646. X     used in advertising or publicity pertaining to  distribution
  647. X     of the software without specific, written prior permission.
  648. X
  649. Written by:
  650. X
  651. X                        Robert C. Pendleton <bobp@hal.com>
  652. X
  653. Grateful acknowledgement is made of code and ideas contributed by
  654. X
  655. X     Ian Donaldson,
  656. X     Department of Communications & Electronic Engineering,
  657. X     Royal Melbourne Institute of Technology,
  658. X     Melbourne, Australia.
  659. X
  660. X$Header: ile.c,v 2.3 88/11/11 10:31:56 bpendlet Exp $
  661. X*/
  662. X
  663. X/*
  664. ile is compiled using:
  665. X
  666. cc ile.c -o ile -ltermcap
  667. X*/
  668. X
  669. X#include <stdio.h>
  670. X#include <fcntl.h>
  671. X#include <sgtty.h>
  672. X#include <signal.h>
  673. X#include <string.h>
  674. X#include <strings.h>
  675. X#include <pwd.h>
  676. X#include <utmp.h>
  677. X#include <errno.h>
  678. X#include <sys/ioctl.h>
  679. X#include <sys/types.h>
  680. X#include <sys/dir.h>
  681. X#include <sys/file.h>
  682. X#include <sys/time.h>
  683. X
  684. X/*------------------------------------------------------------------*/
  685. X/*
  686. Definitions of system stuff.
  687. X*/
  688. X
  689. extern int errno;
  690. X
  691. long lseek();
  692. char *malloc();
  693. char *realloc();
  694. time_t time();
  695. X
  696. X/*------------------------------------------------------------------*/
  697. X
  698. X#define FALSE 0
  699. X#define TRUE  1
  700. X
  701. X#define READ  0
  702. X#define WRITE 1
  703. X#define ERROR 2
  704. X
  705. X#define BUFFER_SIZE 255
  706. X
  707. X#define HISTORY_SIZE 101
  708. X
  709. X#define USER_NAME_SIZE 8
  710. X
  711. X#define EOL (-2)
  712. X/*------------------------------------------------------------------*/
  713. X
  714. X/* special characters used by ile */
  715. X
  716. X#define del '\177'
  717. X
  718. X#define CA '\1'
  719. X#define CB '\2'
  720. X#define CC '\3'
  721. X#define CD '\4'
  722. X#define CE '\5'
  723. X#define CF '\6'
  724. X#define bel '\7'
  725. X#define bs '\10'
  726. X#define CI '\11'
  727. X#define nl '\12'
  728. X#define CK '\13'
  729. X#define CL '\14'
  730. X#define cr '\15'
  731. X#define CN '\16'
  732. X#define CO '\17'
  733. X#define CP '\20'
  734. X#define CQ '\21'
  735. X#define CR '\22'
  736. X#define CS '\23'
  737. X#define CT '\24'
  738. X#define CU '\25'
  739. X#define CV '\26'
  740. X#define CW '\27'
  741. X#define CX '\30'
  742. X#define CY '\31'
  743. X#define CZ '\32'
  744. X
  745. X#define esc '\33'
  746. X
  747. X/*------------------------------------------------------------------*/
  748. X/* areas and varaibles used to get termcap information */
  749. X
  750. char *getenv();
  751. X
  752. char *tgetnum();
  753. char *tgetflag();
  754. char *tgetstr();
  755. X
  756. char termcap_entry[1024];    /* termcap entry for the users terminal */
  757. char term_seqs[1024];        /* area to store control sequences in */
  758. char *where = term_seqs;
  759. X
  760. char *cle;            /* move cursor left one space */
  761. X
  762. char *cce;            /* clear to end of line */
  763. X
  764. char *cbl;            /* audible bell */
  765. X
  766. char *cnl;            /* new line character */
  767. X
  768. char *ccr;            /* carriage return */
  769. X
  770. X/*------------------------------------------------------------------*/
  771. X/*
  772. The value of HOME
  773. X*/
  774. X
  775. char *homedir = NULL;
  776. X
  777. X/*------------------------------------------------------------------*/
  778. X/*
  779. The current working directory as set by query_path.
  780. initialized to PWD
  781. X*/
  782. X
  783. char currentdir[MAXNAMLEN + 1] = "";
  784. X
  785. X/*------------------------------------------------------------------*/
  786. X
  787. X/* tty status flags */
  788. X/*
  789. X  The original tty status flags are stored so that they can be
  790. X  restored when ile exits.
  791. X*/
  792. X
  793. struct sgttyb tty_sgttyb;
  794. struct tchars tty_tchars;
  795. struct ltchars tty_ltchars;
  796. struct winsize tty_winsize;
  797. int windowchanged;
  798. int tty_ldisc;
  799. int tty_mode;
  800. X
  801. X/*------------------------------------------------------------------*/
  802. X
  803. X/* file descriptors for tty and pty */
  804. X
  805. int master_pty;
  806. int slave_tty;
  807. X
  808. X/* the names of the tty and pty opened by getpty */
  809. X
  810. char ttydev[] = "/dev/ttyxx";
  811. char ptydev[] = "/dev/ptyxx";
  812. X
  813. X/* path and name of the lock file */
  814. X
  815. char lock[] = "/tmp/ile.lock";
  816. X
  817. X/*------------------------------------------------------------------*/
  818. X/*
  819. X  getpty opens a pty, storing file descriptors in pty and tty.
  820. X  It trys pairs in order until it finds a pair that is not in use.
  821. X*/
  822. X
  823. getpty(pty, tty)
  824. X    int *pty;
  825. X    int *tty;
  826. X
  827. X{
  828. X    int devindex;
  829. X    int letter;
  830. X
  831. X    static char ptychar1[] = "pqrstuvwxyz";
  832. X    static char ptychar2[] = "0123456789abcdef";
  833. X
  834. X    letter = 0;
  835. X    while (letter < 11)
  836. X    {
  837. X    ttydev[strlen(ttydev) - 2] = ptychar1[letter];
  838. X    ptydev[strlen(ptydev) - 2] = ptychar1[letter];
  839. X    letter++;
  840. X
  841. X    devindex = 0;
  842. X    while (devindex < 16)
  843. X    {
  844. X        ttydev[strlen(ttydev) - 1] = ptychar2[devindex];
  845. X        ptydev[strlen(ptydev) - 1] = ptychar2[devindex];
  846. X        devindex++;
  847. X
  848. X        if ((*pty = open(ptydev, O_RDWR)) >= 0)
  849. X        {
  850. X        if ((*tty = open(ttydev, O_RDWR)) >= 0)
  851. X        {
  852. X            return;
  853. X        }
  854. X        else
  855. X        {
  856. X            (void) close(*pty);
  857. X        }
  858. X        }
  859. X    }
  860. X    }
  861. X
  862. X    (void) fprintf(stderr, "ile: unable to allocate pty/tty pair\n");
  863. X    exit(1);
  864. X    /* NOTREACHED */
  865. X}
  866. X
  867. X/*------------------------------------------------------------------*/
  868. X/*
  869. Termcap entries may have a sequences of digits optionally followed
  870. by a '*' in front of the actual sequence. This routine increments
  871. the pointer past this information.
  872. X*/
  873. void
  874. strip(ptr)
  875. X    char **ptr;
  876. X{
  877. X    while (('0' <= **ptr) && (**ptr <= '9'))
  878. X    {
  879. X    (*ptr)++;
  880. X    }
  881. X
  882. X    if (**ptr == '*')
  883. X    {
  884. X    (*ptr)++;
  885. X    }
  886. X}
  887. X/*------------------------------------------------------------------*/
  888. X/*
  889. Set up everything needed to use the control sequences from the
  890. termcap entry for the terminal.
  891. X*/
  892. void
  893. get_termcap()
  894. X{
  895. X    char *terminal_type;    /* type of terminal */
  896. X
  897. X    /* get the terminal name */
  898. X
  899. X    terminal_type = getenv("TERM");
  900. X
  901. X    /* get termcap entry */
  902. X
  903. X    if (tgetent(termcap_entry, terminal_type) < 1)
  904. X    {
  905. X    (void) fprintf(stderr, "ile: can't find %s\n", terminal_type);
  906. X    exit(1);
  907. X    /* NOTREACHED */
  908. X    }
  909. X
  910. X    /* get the control sequences ile needs */
  911. X
  912. X    if ((cbl = tgetstr("bl", &where)) == NULL)
  913. X    {
  914. X    cbl = "\7";
  915. X    }
  916. X
  917. X    if ((cnl = tgetstr("nl", &where)) == NULL)
  918. X    {
  919. X    cnl = "\n";
  920. X    }
  921. X
  922. X    if ((ccr = tgetstr("cr", &where)) == NULL)
  923. X    {
  924. X    ccr = "\r";
  925. X    }
  926. X
  927. X    if ((cle = tgetstr("le", &where)) == NULL)
  928. X    {
  929. X    if (tgetflag("bs"))
  930. X    {
  931. X        cle = "\b";
  932. X    }
  933. X    }
  934. X
  935. X    if ((cle == NULL) ||
  936. X    ((cce = tgetstr("ce", &where)) == NULL))
  937. X    {
  938. X    (void) fprintf(stderr,
  939. X        "ile: can't run on %s (need capabilities \"le\" and \"ce\")\n",
  940. X        terminal_type);
  941. X    exit(1);
  942. X    /* NOTREACHED */
  943. X    }
  944. X
  945. X    /* strip timing info from strings */
  946. X
  947. X    strip(&cle);
  948. X    strip(&cce);
  949. X    strip(&cbl);
  950. X    strip(&cnl);
  951. X    strip(&ccr);
  952. X}
  953. X/*------------------------------------------------------------------*/
  954. X/*
  955. If the window changes size, tell the slave_tty about it.
  956. X*/
  957. void
  958. change_window()
  959. X{
  960. X    int pgrp;
  961. X
  962. X    (void) ioctl(READ, TIOCGWINSZ, &tty_winsize);
  963. X    (void) ioctl(slave_tty, TIOCSWINSZ, &tty_winsize);
  964. X
  965. X    (void) ioctl(slave_tty, TIOCGPGRP, (char *) &pgrp);
  966. X    (void) killpg(pgrp, SIGWINCH);
  967. X
  968. X    /* note the change so that we don't die after select */
  969. X
  970. X    windowchanged = TRUE;
  971. X}
  972. X/*------------------------------------------------------------------*/
  973. X/*
  974. X * set/clear the utmp slot for the pty
  975. X */
  976. int
  977. setutmp(fd, set)
  978. X{
  979. X    int old0;
  980. X    int old1;
  981. X    int old2;
  982. X    int slot;
  983. X    int f;
  984. X    struct utmp ut;
  985. X
  986. X    /* Must make fd's 0,1,2 correspond to slave_tty for ttyslot() to
  987. X     * function.  Ugh!  Why doesn't ttyslot() accept a fd argument?
  988. X     * 
  989. X     * save fd's */
  990. X
  991. X    old0 = dup(0);
  992. X    old1 = dup(1);
  993. X    old2 = dup(2);
  994. X
  995. X    if (old0 == -1 || old1 == -1 || old2 == -1)
  996. X    {
  997. X    perror("ile: dup");
  998. X    return (-1);        /* file table full ? */
  999. X    }
  1000. X
  1001. X    /* set fd's 0,1,2 for ttyslot() */
  1002. X
  1003. X    (void) dup2(fd, 0);
  1004. X    (void) dup2(fd, 1);
  1005. X    (void) dup2(fd, 2);
  1006. X
  1007. X    slot = ttyslot();
  1008. X
  1009. X    /* put the fd's back */
  1010. X
  1011. X    (void) dup2(old0, 0);
  1012. X    (void) dup2(old1, 1);
  1013. X    (void) dup2(old2, 2);
  1014. X
  1015. X    (void) close(old0);
  1016. X    (void) close(old1);
  1017. X    (void) close(old2);
  1018. X
  1019. X    if (slot < 0)
  1020. X    {
  1021. X    (void) fprintf(stderr, "ile: don't know where you are\n");
  1022. X    return (-1);
  1023. X    }
  1024. X
  1025. X    f = open("/etc/utmp", O_WRONLY);
  1026. X    if (f == -1)
  1027. X    {
  1028. X    return (-1);
  1029. X    }
  1030. X
  1031. X    bzero((char *) &ut, sizeof(ut));
  1032. X
  1033. X    if (set)
  1034. X    {
  1035. X    struct passwd *pw;
  1036. X    char *cp;
  1037. X
  1038. X    pw = getpwuid(getuid());
  1039. X    if (pw == 0)
  1040. X    {
  1041. X        (void) fprintf(stderr, "ile: who are you?\n");
  1042. X        (void) close(f);
  1043. X        return (-1);
  1044. X    }
  1045. X
  1046. X    /* skip "/dev/" */
  1047. X
  1048. X    cp = rindex(ttydev, '/');
  1049. X    if (cp == 0)
  1050. X    {
  1051. X        cp = ttydev;
  1052. X    }
  1053. X    else
  1054. X    {
  1055. X        cp++;
  1056. X    }
  1057. X
  1058. X    (void) strncpy(ut.ut_line, cp, sizeof(ut.ut_line));
  1059. X    (void) strncpy(ut.ut_name, pw->pw_name, sizeof(ut.ut_line));
  1060. X    (void) time(&ut.ut_time);
  1061. X    }
  1062. X    (void) lseek(f, (long) (slot * sizeof(struct utmp)), L_SET);
  1063. X    (void) write(f, (char *) &ut, sizeof(ut));
  1064. X    (void) close(f);
  1065. X
  1066. X    return (0);
  1067. X}
  1068. X/*------------------------------------------------------------------*/
  1069. X/*
  1070. clean up and leave.
  1071. X
  1072. This function is bound to the SIGCHLD signal so that when the
  1073. child process exits, so does ile. It is also called when an exception
  1074. is detected by select() in ile().
  1075. X*/
  1076. void
  1077. clean_up()
  1078. X{
  1079. X    int pgrp;
  1080. X
  1081. X    /* kill off the child process */
  1082. X
  1083. X    (void) ioctl(slave_tty, TIOCGPGRP, (char *) &pgrp);
  1084. X    (void) killpg(pgrp, SIGTERM);
  1085. X
  1086. X    /* restore terminal status */
  1087. X
  1088. X    (void) ioctl(READ, TIOCSETP, &tty_sgttyb);
  1089. X    (void) ioctl(READ, TIOCSETC, &tty_tchars);
  1090. X    (void) ioctl(READ, TIOCSLTC, &tty_ltchars);
  1091. X    (void) ioctl(READ, TIOCLSET, &tty_mode);
  1092. X
  1093. X    /* "logout" the user */
  1094. X
  1095. X    (void) setutmp(slave_tty, FALSE);
  1096. X
  1097. X    /* clean up the tty/pty pair */
  1098. X
  1099. X    (void) close(master_pty);
  1100. X    (void) close(slave_tty);
  1101. X
  1102. X    /* make things look nice */
  1103. X
  1104. X    fputs(cnl, stdout);
  1105. X
  1106. X    exit(0);
  1107. X    /* NOTREACHED */
  1108. X}
  1109. X/*------------------------------------------------------------------*/
  1110. X/*
  1111. Write a line to the slave_tty.
  1112. Get the slave_tty parameters, turn off echo, send the line to the
  1113. slave_tty, restore the slave_tty paramters to the way they were
  1114. before. If echo was already off, this will have no effect.
  1115. X*/
  1116. write_line(line, length)
  1117. X    char *line;
  1118. X    int length;
  1119. X{
  1120. X    struct sgttyb params;
  1121. X    struct sgttyb new_params;
  1122. X
  1123. X    /* get the current parameters */
  1124. X
  1125. X    (void) ioctl(slave_tty, TIOCGETP, ¶ms);
  1126. X    new_params = params;
  1127. X    new_params.sg_flags &= ~ECHO;
  1128. X
  1129. X    /* turn off echo so we don't see the characters twice */
  1130. X
  1131. X    (void) ioctl(slave_tty, TIOCSETP, &new_params);
  1132. X
  1133. X    (void) write(master_pty, line, length);
  1134. X
  1135. X    /* set the parameters back the way they were */
  1136. X
  1137. X    (void) ioctl(slave_tty, TIOCSETN, ¶ms);
  1138. X}
  1139. X
  1140. X/*------------------------------------------------------------------*/
  1141. X/*
  1142. The editing routines are called through the edit variable. This allows
  1143. the quote and escape commands to be implemented as a straight forward
  1144. state machine instead of requiring state flags and complex switch
  1145. statements.
  1146. X*/
  1147. X/*------------------------------------------------------------------*/
  1148. X
  1149. X/* line edit buffer */
  1150. X
  1151. static char line[BUFFER_SIZE];
  1152. X
  1153. static int point;        /* insertion point */
  1154. static int length;        /* total chars in buffer */
  1155. X
  1156. X/* procedure to edit next character */
  1157. X
  1158. void (*edit) ();
  1159. X
  1160. X/* history buffer */
  1161. X
  1162. struct
  1163. X{
  1164. X    int length;
  1165. X    char *line;
  1166. X} hist[HISTORY_SIZE];
  1167. X
  1168. int head;            /* insertion point */
  1169. int here;            /* current displayed line */
  1170. X
  1171. X/*------------------------------------------------------------------*/
  1172. X/*
  1173. The delimiter vector is used by the forward, backward, and delete
  1174. word operations to decide that a character is a delimiter.
  1175. X*/
  1176. X/*------------------------------------------------------------------*/
  1177. X
  1178. X#define CHAR_SET_SIZE 127
  1179. X#define CHAR_MASK 0177
  1180. X
  1181. char delimit[CHAR_SET_SIZE];
  1182. X
  1183. X/*------------------------------------------------------------------*/
  1184. X/*
  1185. The action_table is used to bind sequences of keys to operations or strings.
  1186. X*/
  1187. X/*------------------------------------------------------------------*/
  1188. X
  1189. typedef enum
  1190. X{
  1191. X    is_action, is_string
  1192. X} action_type;
  1193. X
  1194. struct
  1195. X{
  1196. X    action_type flag;
  1197. X    union
  1198. X    {
  1199. X    void (*action) ();
  1200. X    char *string;
  1201. X    } aors;
  1202. X} action_table[4][CHAR_SET_SIZE];
  1203. X
  1204. X/*------------------------------------------------------------------*/
  1205. X
  1206. void echo();
  1207. void echoline();
  1208. void cleartoend();
  1209. void clearline();
  1210. void backspace();
  1211. void quote_edit();
  1212. void edit_0();
  1213. void edit_1();
  1214. void edit_2();
  1215. void edit_3();
  1216. void bell();
  1217. void insert();
  1218. X
  1219. X/*------------------------------------------------------------------*/
  1220. X/*
  1221. The following routines are action routines that are executed by the
  1222. editor to carry out commands. Each routine has a single character
  1223. argument. Each routine is invoked with the character that caused it
  1224. to be invoked as its argument.
  1225. X
  1226. The argument isn't always useful, but it is included to provide a
  1227. consistent interface for the routines.
  1228. X*/
  1229. X/*------------------------------------------------------------------*/
  1230. X/*
  1231. Given a specific directory and the starting string of a file name,
  1232. find the longest partial file name that starts with the substring.
  1233. X*/
  1234. void
  1235. complete_file_name(dir, name)
  1236. X    char *dir;
  1237. X    char *name;
  1238. X{
  1239. X    DIR *dirp;
  1240. X    struct direct *dp;
  1241. X
  1242. X    int len;
  1243. X    int maxlen;
  1244. X    int oldlen;
  1245. X
  1246. X    char oldname[MAXNAMLEN + 1];
  1247. X    char newname[MAXNAMLEN + 1];
  1248. X
  1249. X    if ((dir != NULL) &&
  1250. X    (name != NULL) &&
  1251. X    ((oldlen = strlen(name)) > 0) &&
  1252. X    ((dirp = opendir(dir)) != NULL))
  1253. X    {
  1254. X    maxlen = oldlen;
  1255. X    (void) strcpy(oldname, name);
  1256. X    (void) strcpy(newname, name);
  1257. X
  1258. X    /* find the longest name starting with name */
  1259. X
  1260. X    for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
  1261. X    {
  1262. X        if (dp->d_name != NULL)
  1263. X        {
  1264. X        len = strlen(dp->d_name);
  1265. X        if ((maxlen < len) &&
  1266. X            (strncmp(oldname, dp->d_name, oldlen) == 0))
  1267. X        {
  1268. X            maxlen = len;
  1269. X            (void) strcpy(newname, dp->d_name);
  1270. X        }
  1271. X        }
  1272. X    }
  1273. X
  1274. X    rewinddir(dirp);
  1275. X
  1276. X    /* find the longest common sub string */
  1277. X
  1278. X    for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
  1279. X    {
  1280. X        if (dp->d_name != NULL)
  1281. X        {
  1282. X        len = strlen(dp->d_name);
  1283. X        if ((len <= maxlen) &&
  1284. X            (strncmp(oldname, dp->d_name, oldlen) == 0))
  1285. X        {
  1286. X            for (;
  1287. X            (oldlen < len) &&
  1288. X            (strncmp(newname, dp->d_name, len) != 0);
  1289. X            len--);
  1290. X
  1291. X            maxlen = len;
  1292. X            newname[maxlen] = '\0';
  1293. X        }
  1294. X        }
  1295. X    }
  1296. X
  1297. X    if (strlen(name) != strlen(newname))
  1298. X    {
  1299. X        /* return the extended name */
  1300. X
  1301. X        (void) strcpy(name, newname);
  1302. X    }
  1303. X    else
  1304. X    {
  1305. X        /* no difference so beep */
  1306. X
  1307. X        bell('\0');
  1308. X    }
  1309. X
  1310. X    (void) closedir(dirp);
  1311. X    }
  1312. X}
  1313. X/*------------------------------------------------------------------*/
  1314. X/*
  1315. Hidden parameters to dirselect. They must be hidden because dirselect
  1316. is passed as an argument to scandir.
  1317. X*/
  1318. X
  1319. static char *namep;
  1320. static int namelen;
  1321. X
  1322. X/*------------------------------------------------------------------*/
  1323. X/*
  1324. Passed to scandir. It is used to decide which files to display.
  1325. X*/
  1326. X
  1327. static
  1328. dirselect(dp)
  1329. X    struct direct *dp;
  1330. X{
  1331. X    return (strncmp(dp->d_name, namep, namelen) == 0);
  1332. X}
  1333. X
  1334. X/*------------------------------------------------------------------*/
  1335. X/*
  1336. List all the files in a given directory that start with the string
  1337. passed as name.
  1338. X*/
  1339. void
  1340. list_file_names(dir, name)
  1341. X    char *dir;
  1342. X    char *name;
  1343. X{
  1344. X    struct direct **dlist;
  1345. X    int i;
  1346. X    int nfiles;
  1347. X    int colwidth;
  1348. X    int cols;
  1349. X    int ncols;
  1350. X    int nlines;
  1351. X    int alphasort();
  1352. X
  1353. X    if (dir == NULL || name == NULL)
  1354. X    {
  1355. X    return;
  1356. X    }
  1357. X
  1358. X    cols = tty_winsize.ws_col;
  1359. X    if (cols <= 0)
  1360. X    {
  1361. X    cols = 80;
  1362. X    }
  1363. X
  1364. X    namelen = strlen(name);
  1365. X    namep = name;
  1366. X
  1367. X    nfiles = scandir(dir, &dlist, dirselect, alphasort);
  1368. X
  1369. X    /* determine the longest file name length */
  1370. X
  1371. X    colwidth = 8;        /* minimum width */
  1372. X    for (i = 0; i < nfiles; i++)
  1373. X    {
  1374. X    struct direct *dp;
  1375. X
  1376. X    dp = dlist[i];
  1377. X
  1378. X    if (dp->d_namlen > colwidth)
  1379. X    {
  1380. X        colwidth = dp->d_namlen;
  1381. X    }
  1382. X    }
  1383. X
  1384. X    colwidth++;            /* at least 1 space between them */
  1385. X
  1386. X    /* print the names, sorted vertically per column */
  1387. X    ncols = cols / colwidth;
  1388. X    if (ncols == 0)
  1389. X    {
  1390. X    /* longest filename is wider than the screen */
  1391. X    ncols = 1;
  1392. X    }
  1393. X
  1394. X    nlines = (nfiles + ncols - 1) / ncols;
  1395. X
  1396. X    if (nfiles > 0)
  1397. X    {
  1398. X    for (i = 0; i < nlines; i++)
  1399. X    {
  1400. X        int j;
  1401. X        int l;
  1402. X
  1403. X        l = 0;
  1404. X        for (j = 0; j < ncols; j++)
  1405. X        {
  1406. X        int m;
  1407. X        struct direct *dp;
  1408. X
  1409. X        m = l + i;
  1410. X        if (m >= nfiles)
  1411. X        {
  1412. X            break;
  1413. X        }
  1414. X
  1415. X        dp = dlist[m];
  1416. X        fputs(dp->d_name, stdout);
  1417. X
  1418. X        if (j < (ncols - 1))
  1419. X        {
  1420. X            int k;
  1421. X
  1422. X            for (k = dp->d_namlen; k < colwidth; k++)
  1423. X            {
  1424. X            (void) fputc(' ', stdout);
  1425. X            }
  1426. X            l += nlines;
  1427. X        }
  1428. X        }
  1429. X        fputs(ccr, stdout);
  1430. X        fputs(cnl, stdout);
  1431. X    }
  1432. X    }
  1433. X    free((char *) dlist);
  1434. X}
  1435. X/*------------------------------------------------------------------*/
  1436. X/*
  1437. Assuming that there is a file name under the cursor, return a path
  1438. and a file name. If there is no path name return "."
  1439. X*/
  1440. int
  1441. get_dir_and_name(dir, name, username, userend, start, middle, tail)
  1442. X    char *dir;
  1443. X    char *name;
  1444. X    char *username;
  1445. X    int *userend;
  1446. X    int *start;
  1447. X    int *middle;
  1448. X    int *tail;
  1449. X{
  1450. X    int dirlen;
  1451. X
  1452. X    int newstart;
  1453. X
  1454. X    int punlen;
  1455. X    char pun[USER_NAME_SIZE + 1];
  1456. X    struct passwd *userpwd;
  1457. X
  1458. X    int i;
  1459. X
  1460. X    /* set the default path and file name */
  1461. X
  1462. X    dir[0] = '\0';
  1463. X    name[0] = '\0';
  1464. X    username[0] = '\0';
  1465. X
  1466. X    /* search for the start of the file name */
  1467. X    /* start will be left pointing to the first character of the path  */
  1468. X
  1469. X    for ((*start) = point;
  1470. X    ((0 < (*start)) && (line[(*start) - 1] != ' '));
  1471. X    (*start)--
  1472. X    );
  1473. X
  1474. X    /* search for the end of the file name */
  1475. X    /* tail will be left pointing at the last character of the path */
  1476. X
  1477. X    for ((*tail) = point - 1;
  1478. X    (((*tail) < (length - 1)) && (line[(*tail) + 1] != ' '));
  1479. X    (*tail)++
  1480. X    );
  1481. X
  1482. X    /* search for the middle of the file name */
  1483. X    /* middle will be left pointing at the first character of the last
  1484. X     * element of the path */
  1485. X
  1486. X    for ((*middle) = (*tail) + 1;
  1487. X    ((0 < (*middle)) &&
  1488. X        (line[(*middle) - 1] != '/') &&
  1489. X        (line[(*middle) - 1] != ' '));
  1490. X    (*middle)--
  1491. X    );
  1492. X
  1493. X    /* copy path from line to dir */
  1494. X
  1495. X    /* what base path */
  1496. X
  1497. X    newstart = (*start);
  1498. X
  1499. X    if ((line[newstart] == '~') &&
  1500. X    ((newstart + 1) < length) &&
  1501. X    (line[newstart + 1] == '/'))
  1502. X    {
  1503. X    /* "~/" means use the value of HOME */
  1504. X
  1505. X    newstart++;
  1506. X    (void) strcpy(dir, homedir);
  1507. X    }
  1508. X    else if (line[newstart] == '~')
  1509. X    {
  1510. X    /* "~username" means use the users login directory */
  1511. X
  1512. X    /* search for the end of the user name */
  1513. X
  1514. X    for ((*userend) = newstart,
  1515. X        punlen = 0;
  1516. X        (((*userend) < (length - 1)) &&
  1517. X        (line[(*userend) + 1] != ' ') &&
  1518. X        (line[(*userend) + 1] != '/'));
  1519. X        (*userend)++,
  1520. X        punlen++);
  1521. X
  1522. X    /* make middle point to middle */
  1523. X
  1524. X    if ((*start) == (*middle))
  1525. X    {
  1526. X        (*middle) = (*start) + punlen + 1;
  1527. X    }
  1528. X
  1529. X    /* extract partial user name from line */
  1530. X
  1531. X    (void) strncpy(pun, &line[newstart + 1], punlen);
  1532. X    pun[punlen] = '\0';
  1533. X
  1534. X    /* search passwd file for partial match */
  1535. X
  1536. X    for (userpwd = getpwent();
  1537. X        userpwd != NULL;
  1538. X        userpwd = getpwent())
  1539. X    {
  1540. X        if ((punlen <= strlen(userpwd->pw_name)) &&
  1541. X        (strncmp(pun, userpwd->pw_name, punlen) == 0))
  1542. X        {
  1543. X
  1544. X        /* we have a partial match, record it */
  1545. X
  1546. X        if (strlen(dir) == 0)
  1547. X        {
  1548. X            newstart = (*userend) + 1;
  1549. X            (void) strcpy(dir, userpwd->pw_dir);
  1550. X            (void) strcpy(username, userpwd->pw_name);
  1551. X        }
  1552. X        else
  1553. X        {
  1554. X            /* second partial match, forget the first one. */
  1555. X
  1556. X            newstart = (*start);
  1557. X            dir[0] = '\0';
  1558. X            username[0] = '\0';
  1559. X            return (FALSE);
  1560. X        }
  1561. X
  1562. X        }
  1563. X    }
  1564. X    (void) setpwent();
  1565. X    }
  1566. X    else if ((line[newstart] == '.') &&
  1567. X        ((newstart + 1) < length) &&
  1568. X    (line[newstart + 1] == '/'))
  1569. X    {
  1570. X    /* if it's "./" use current dir */
  1571. X
  1572. X    newstart++;
  1573. X    (void) strcpy(dir, currentdir);
  1574. X    }
  1575. X    else if ((line[newstart] == '.') &&
  1576. X        ((newstart + 1) < length) &&
  1577. X        (line[newstart + 1] == '.') &&
  1578. X        ((newstart + 2) < length) &&
  1579. X    (line[newstart + 2] == '/'))
  1580. X    {
  1581. X    /* if it's "../" strip off one name from currentdir and use that */
  1582. X
  1583. X    newstart += 2;
  1584. X    (void) strcpy(dir, currentdir);
  1585. X    for (i = strlen(dir); (i > 0) && (dir[i] != '/'); i--)
  1586. X    {
  1587. X        /* nothing */
  1588. X    }
  1589. X    dir[i] = '\0';
  1590. X    }
  1591. X    else if (line[newstart] != '/')
  1592. X    {
  1593. X    /* doesn't start with a "/"? use currentdir */
  1594. X
  1595. X    (void) strcpy(dir, currentdir);
  1596. X    (void) strcat(dir, "/");
  1597. X    }
  1598. X
  1599. X    /* add on the rest of the path */
  1600. X
  1601. X    dirlen = strlen(dir);
  1602. X    for (i = 0; i < ((*middle) - newstart); i++)
  1603. X    {
  1604. X    dir[dirlen + i] = line[newstart + i];
  1605. X    }
  1606. X    dir[dirlen + i] = '\0';
  1607. X
  1608. X    /* copy file name from line to name */
  1609. X
  1610. X    for (i = 0; i < ((*tail) - (*middle) + 1); i++)
  1611. X    {
  1612. X    name[i] = line[(*middle) + i];
  1613. X    }
  1614. X    name[i] = '\0';
  1615. X
  1616. X    return (TRUE);
  1617. X}
  1618. X/*------------------------------------------------------------------*/
  1619. X/*
  1620. Perform file name completion. Put the full path and file name in the
  1621. line.
  1622. X*/
  1623. X/*ARGSUSED*/
  1624. void
  1625. complete_file_full(ch)
  1626. X    char ch;
  1627. X{
  1628. X    char dir[10 * (MAXNAMLEN + 1)];
  1629. X    char name[MAXNAMLEN + 1];
  1630. X    char username[USER_NAME_SIZE + 1];
  1631. X
  1632. X    char newline[BUFFER_SIZE];
  1633. X    int newlength;
  1634. X    int newpoint;
  1635. X
  1636. X    int userend;
  1637. X    int start;
  1638. X    int middle;
  1639. X    int tail;
  1640. X
  1641. X    int i;
  1642. X
  1643. X    /* get the path and file name in the line */
  1644. X
  1645. X    if (get_dir_and_name(dir,
  1646. X        name,
  1647. X        username,
  1648. X        &userend,
  1649. X        &start,
  1650. X        &middle,
  1651. X        &tail))
  1652. X    {
  1653. X
  1654. X    /* complete the file name if possible */
  1655. X
  1656. X    complete_file_name(dir, name);
  1657. X
  1658. X    /* create a new line */
  1659. X
  1660. X    /* start with the line prefix */
  1661. X
  1662. X    (void) strncpy(newline, line, start);
  1663. X    newline[start] = '\0';
  1664. X
  1665. X    /* add in the new path */
  1666. X
  1667. X    (void) strcat(newline, dir);
  1668. X
  1669. X    /* stick in the new file name */
  1670. X
  1671. X    (void) strcat(newline, name);
  1672. X    newpoint = strlen(newline);
  1673. X
  1674. X    /* finish with the line postfix */
  1675. X
  1676. X    (void) strncat(newline, &line[tail + 1], (length - tail - 1));
  1677. X    newlength = strlen(newline);
  1678. X
  1679. X    /* display the new line */
  1680. X
  1681. X    clearline('\0');
  1682. X
  1683. X    point = newpoint;
  1684. X    length = newlength;
  1685. X    (void) strncpy(line, newline, newlength);
  1686. X
  1687. X    echoline(line, length);
  1688. X
  1689. X    for (i = point; i < length; i++)
  1690. X    {
  1691. X        backspace(line[i]);
  1692. X    }
  1693. X    }
  1694. X    else
  1695. X    {
  1696. X    bell('\0');
  1697. X    }
  1698. X}
  1699. X/*------------------------------------------------------------------*/
  1700. X/*
  1701. Perform file name completion in much the same style as csh.
  1702. X*/
  1703. X/*ARGSUSED*/
  1704. void
  1705. complete_file(ch)
  1706. X    char ch;
  1707. X{
  1708. X    char dir[10 * (MAXNAMLEN + 1)];
  1709. X    char name[MAXNAMLEN + 1];
  1710. X    char username[USER_NAME_SIZE + 1];
  1711. X
  1712. X    int userend;
  1713. X    int start;
  1714. X    int middle;
  1715. X    int tail;
  1716. X
  1717. X    char newline[BUFFER_SIZE];
  1718. X    int newlength;
  1719. X    int newpoint;
  1720. X
  1721. X    int userlen;
  1722. X    int len;
  1723. X
  1724. X    int i;
  1725. X
  1726. X    /* get the path and file name in the line */
  1727. X
  1728. X    if (get_dir_and_name(dir,
  1729. X        name,
  1730. X        username,
  1731. X        &userend,
  1732. X        &start,
  1733. X        &middle,
  1734. X        &tail))
  1735. X    {
  1736. X    /* how long is the user name */
  1737. X
  1738. X    userlen = strlen(username);
  1739. X
  1740. X    /* complete the file name if possible */
  1741. X
  1742. X    complete_file_name(dir, name);
  1743. X    /* create a new line */
  1744. X
  1745. X    /* start with the line prefix */
  1746. X
  1747. X    (void) strncpy(newline, line, start);
  1748. X    newline[start] = '\0';
  1749. X
  1750. X    /* add in the new username */
  1751. X
  1752. X    if (userlen != 0)
  1753. X    {
  1754. X        /* put in new user name */
  1755. X
  1756. X        (void) strcat(newline, "~");
  1757. X        (void) strcat(newline, username);
  1758. X        len = strlen(newline);
  1759. X
  1760. X        /* put in the existing path */
  1761. X
  1762. X        (void) strncat(newline, &line[userend + 1], middle - userend - 1);
  1763. X        newline[len + (middle - userend - 1)] = '\0';
  1764. X    }
  1765. X    else
  1766. X    {
  1767. X        /* put in the existing path */
  1768. X
  1769. X        len = strlen(newline);
  1770. X        (void) strncat(newline, &line[start], middle - start);
  1771. X        newline[len + (middle - start)] = '\0';
  1772. X    }
  1773. X
  1774. X    /* stick in the new file name */
  1775. X
  1776. X    (void) strcat(newline, name);
  1777. X    newpoint = strlen(newline);
  1778. X
  1779. X    /* finish with the line postfix */
  1780. X
  1781. X    (void) strncat(newline, &line[tail + 1], (length - tail - 1));
  1782. X    newlength = strlen(newline);
  1783. X
  1784. X    /* display the new line */
  1785. X
  1786. X    clearline('\0');
  1787. X
  1788. X    point = newpoint;
  1789. X    length = newlength;
  1790. X    (void) strncpy(line, newline, newlength);
  1791. X
  1792. X    echoline(line, length);
  1793. X
  1794. X    for (i = point; i < length; i++)
  1795. X    {
  1796. X        backspace(line[i]);
  1797. X    }
  1798. X    }
  1799. X    else
  1800. X    {
  1801. X    bell('\0');
  1802. X    }
  1803. X}
  1804. X/*------------------------------------------------------------------*/
  1805. X/*
  1806. List the names of files that start with the directory path and
  1807. file name under the cursor.
  1808. X*/
  1809. X/*ARGSUSED*/
  1810. void
  1811. show_files(ch)
  1812. X    char ch;
  1813. X{
  1814. X    static char divider[] = "----------";
  1815. X
  1816. X    void retype_line();
  1817. X
  1818. X    char dir[10 * (MAXNAMLEN + 1)];
  1819. X    char name[MAXNAMLEN + 1];
  1820. X    char username[USER_NAME_SIZE + 1];
  1821. X
  1822. X    int userend;
  1823. X    int start;
  1824. X    int middle;
  1825. X    int tail;
  1826. X
  1827. X    if (get_dir_and_name(dir,
  1828. X        name,
  1829. X        username,
  1830. X        &userend,
  1831. X        &start,
  1832. X        &middle,
  1833. X        &tail))
  1834. X    {
  1835. X
  1836. X    fputs(ccr, stdout);
  1837. X    fputs(cnl, stdout);
  1838. X
  1839. X    fputs(divider, stdout);
  1840. X
  1841. X    fputs(ccr, stdout);
  1842. X    fputs(cnl, stdout);
  1843. X
  1844. X    list_file_names(dir, name);
  1845. X
  1846. X    fputs(divider, stdout);
  1847. X
  1848. X    fputs(ccr, stdout);
  1849. X    fputs(cnl, stdout);
  1850. X
  1851. X    retype_line('\0');
  1852. X    }
  1853. X    else
  1854. X    {
  1855. X    bell('\0');
  1856. X    }
  1857. X}
  1858. X/*------------------------------------------------------------------*/
  1859. X/*
  1860. Make the gross assumption that the program we are talking to is
  1861. a shell and send "pwd\n" to it. Whatever comes back is saved as the
  1862. value of currentdir.
  1863. X*/
  1864. X/*ARGSUSED*/
  1865. void
  1866. query_path(ch)
  1867. X    char ch;
  1868. X{
  1869. X    static char command[] = "pwd\n";
  1870. X    char buffer[BUFFER_SIZE];
  1871. X    int readfd;
  1872. X    struct timeval timeout;
  1873. X    int status;
  1874. X    int cc;
  1875. X    int i;
  1876. X
  1877. X    /* send the command to the shell, we hope. */
  1878. X
  1879. X    write_line(command, strlen(command));
  1880. X
  1881. X    /* read the directory path back */
  1882. X
  1883. X    readfd = 1 << master_pty;
  1884. X    timeout.tv_sec = 2;
  1885. X    timeout.tv_usec = 0;
  1886. X
  1887. X    do
  1888. X    {
  1889. X    status = select(32,
  1890. X        (fd_set *) & readfd,
  1891. X        (fd_set *) NULL,
  1892. X        (fd_set *) NULL,
  1893. X        &timeout);
  1894. X
  1895. X    if (0 < status)
  1896. X    {
  1897. X        cc = read(master_pty, currentdir, sizeof(currentdir));
  1898. X
  1899. X        /* strip off trailing control chars and blanks */
  1900. X
  1901. X        for (i = cc - 1; (currentdir[i] <= ' ') && (i > 0); i--)
  1902. X        {
  1903. X        currentdir[i] = '\0';
  1904. X        }
  1905. X
  1906. X        /* read the prompt so it can be ignored */
  1907. X
  1908. X        readfd = 1 << master_pty;
  1909. X        timeout.tv_sec = 2;
  1910. X        timeout.tv_usec = 0;
  1911. X
  1912. X        do
  1913. X        {
  1914. X        status = select(32,
  1915. X            (fd_set *) & readfd,
  1916. X            (fd_set *) NULL,
  1917. X            (fd_set *) NULL,
  1918. X            &timeout);
  1919. X
  1920. X        if (0 < status)
  1921. X        {
  1922. X            cc = read(master_pty, buffer, sizeof(buffer));
  1923. X        }
  1924. X        else if ((-1 == status) && windowchanged)
  1925. X        {
  1926. X            windowchanged = FALSE;
  1927. X        }
  1928. X        } while (status == -1);
  1929. X    }
  1930. X    else if ((-1 == status) && windowchanged)
  1931. X    {
  1932. X        windowchanged = FALSE;
  1933. X    }
  1934. X    } while (status == -1);
  1935. X}
  1936. X/*------------------------------------------------------------------*/
  1937. X/*
  1938. Ring the bell on the terminal.
  1939. X*/
  1940. X/*ARGSUSED*/
  1941. void
  1942. bell(ch)
  1943. X    char ch;
  1944. X{
  1945. X    fputs(cbl, stdout);
  1946. X}
  1947. X/*------------------------------------------------------------------*/
  1948. X/*
  1949. Pass characters to the slave. Don't mess with them at all.
  1950. X*/
  1951. void
  1952. pass(ch)
  1953. X    char ch;
  1954. X{
  1955. X    (void) write(master_pty, &ch, 1);
  1956. X}
  1957. X/*------------------------------------------------------------------*/
  1958. X/*
  1959. Insert a character at point in the line buffer. While we are at it
  1960. update the display to show the insertion.
  1961. X*/
  1962. void
  1963. insert(ch)
  1964. X    char ch;
  1965. X{
  1966. X    int i;
  1967. X
  1968. X    if (length < (BUFFER_SIZE - 2))
  1969. X    {
  1970. X
  1971. X    /* display the character */
  1972. X
  1973. X    echo(ch);
  1974. X
  1975. X    /* redisplay the rest of the line */
  1976. X
  1977. X    echoline(&line[point], (length - point));
  1978. X
  1979. X    /* move the characters in the line buffer */
  1980. X    /* and put the cursor back at point */
  1981. X
  1982. X    for (i = length; i > point; i--)
  1983. X    {
  1984. X        line[i] = line[i - 1];
  1985. X        backspace(line[i]);
  1986. X    }
  1987. X
  1988. X    /* add the character to the line buffer */
  1989. X    /* and increment point and length */
  1990. X
  1991. X    line[point] = ch;
  1992. X    length++;
  1993. X    point++;
  1994. X    }
  1995. X    else
  1996. X    {
  1997. X    bell('\0');
  1998. X    }
  1999. X}
  2000. X/*------------------------------------------------------------------*/
  2001. X/*
  2002. Transpose the letter under the cursor and the letter immediately to
  2003. the left of the cursor.
  2004. X*/
  2005. X/*ARGSUSED*/
  2006. void
  2007. transpose_chars(ch)
  2008. X    char ch;
  2009. X{
  2010. X    char tch;
  2011. X
  2012. X    if ((0 < point) && (point < length))
  2013. X    {
  2014. X    /* first, update the display */
  2015. X
  2016. X    backspace(line[point]);
  2017. X
  2018. X    echo(line[point]);
  2019. X    echo(line[point - 1]);
  2020. X
  2021. X    /* now swap the chars in the line buffer */
  2022. X
  2023. X    tch = line[point];
  2024. X    line[point] = line[point - 1];
  2025. X    line[point - 1] = tch;
  2026. X
  2027. X    /* point moved forward one char */
  2028. X
  2029. X    point++;
  2030. X    }
  2031. X}
  2032. X/*------------------------------------------------------------------*/
  2033. X/*
  2034. Delete a character at point in the line buffer. While we are at it
  2035. update the display to reflect the deletion.
  2036. X*/
  2037. X/*ARGSUSED*/
  2038. void
  2039. delete_char_under(ch)
  2040. X    char ch;
  2041. X{
  2042. X    int i;
  2043. X
  2044. X    if (point < length)
  2045. X    {
  2046. X
  2047. X    /* clear to the end of the line */
  2048. X
  2049. X    cleartoend();
  2050. X
  2051. X    /* retype the rest of the line */
  2052. X
  2053. X    echoline(&line[point + 1], (length - point - 1));
  2054. X
  2055. X    /* build the new line */
  2056. X
  2057. X    for (i = point + 1; i < length; i++)
  2058. X    {
  2059. X        line[i - 1] = line[i];
  2060. X        backspace(line[i]);
  2061. X    }
  2062. X
  2063. X    length--;
  2064. X
  2065. X    if (point > length)
  2066. X    {
  2067. X        point = length;
  2068. X    }
  2069. X    }
  2070. X
  2071. X}
  2072. X/*------------------------------------------------------------------*/
  2073. X/*
  2074. Delete the character to the left of point in the line buffer. While we
  2075. are at it update the display to reflect the deletion.
  2076. X*/
  2077. X/*ARGSUSED*/
  2078. void
  2079. delete_char(ch)
  2080. X    char ch;
  2081. X{
  2082. X    int i;
  2083. X
  2084. X    if (point > 0)
  2085. X    {
  2086. X    /* move the cursor left one character */
  2087. X
  2088. X    backspace(line[point - 1]);
  2089. X
  2090. X    /* clear to the end of the line */
  2091. X
  2092. X    cleartoend();
  2093. X
  2094. X    /* retype the rest of the line */
  2095. X
  2096. X    echoline(&line[point], (length - point));
  2097. X
  2098. X    /* build the new line */
  2099. X
  2100. X    for (i = point; i < length; i++)
  2101. X    {
  2102. X        line[i - 1] = line[i];
  2103. X        backspace(line[i]);
  2104. X    }
  2105. X
  2106. X    length--;
  2107. X    point--;
  2108. X    }
  2109. X
  2110. X}
  2111. X/*------------------------------------------------------------------*/
  2112. X/*
  2113. Bind the edit vector to quote_edit so that the next character
  2114. will be placed in the line buffer.
  2115. X*/
  2116. X/*ARGSUSED*/
  2117. void
  2118. quote(ch)
  2119. X    char ch;
  2120. X{
  2121. X    edit = quote_edit;
  2122. X}
  2123. X/*------------------------------------------------------------------*/
  2124. X/*
  2125. The next character will select an action from action_table[1]
  2126. X*/
  2127. X/*ARGSUSED*/
  2128. void
  2129. escape_1(ch)
  2130. X    char ch;
  2131. X{
  2132. X    edit = edit_1;
  2133. X}
  2134. X/*------------------------------------------------------------------*/
  2135. X/*
  2136. The next character will select an action from action_table[2]
  2137. X*/
  2138. X/*ARGSUSED*/
  2139. void
  2140. escape_2(ch)
  2141. X    char ch;
  2142. X{
  2143. X    edit = edit_2;
  2144. X}
  2145. X/*------------------------------------------------------------------*/
  2146. X/*
  2147. The next character will select an action from action_table[3]
  2148. X*/
  2149. X/*ARGSUSED*/
  2150. void
  2151. escape_3(ch)
  2152. X    char ch;
  2153. X{
  2154. X    edit = edit_3;
  2155. X}
  2156. X/*------------------------------------------------------------------*/
  2157. X/*
  2158. Delete the word to the left of the cursor.
  2159. X*/
  2160. X/*ARGSUSED*/
  2161. void
  2162. delete_word(ch)
  2163. X    char ch;
  2164. X{
  2165. X    int i;
  2166. X    int old;
  2167. X
  2168. X    if (length > 0)
  2169. X    {
  2170. X    /* find the new deletion point */
  2171. X
  2172. X    old = point;
  2173. X
  2174. X    /* first skip over any delimiters */
  2175. X
  2176. X    for (; (point > 0) && (delimit[line[point - 1]]); point--)
  2177. X    {
  2178. X        backspace(line[point - 1]);
  2179. X    }
  2180. X
  2181. X    /* now delete until we find a delimiter */
  2182. X
  2183. X    for (; (point > 0) && (!delimit[line[point - 1]]); point--)
  2184. X    {
  2185. X        backspace(line[point - 1]);
  2186. X    }
  2187. X
  2188. X    /* clear to the end of the line */
  2189. X
  2190. X    cleartoend();
  2191. X
  2192. X    /* retype the rest of the line */
  2193. X
  2194. X    echoline(&line[old], (length - old));
  2195. X
  2196. X    /* construct the new line */
  2197. X
  2198. X    for (i = 0; i < (length - old); i++)
  2199. X    {
  2200. X        line[point + i] = line[old + i];
  2201. X        backspace(line[point + i]);
  2202. X    }
  2203. X
  2204. X    /* update the length */
  2205. X
  2206. X    length = length - (old - point);
  2207. X    }
  2208. X}
  2209. X/*------------------------------------------------------------------*/
  2210. X/*
  2211. Go forward one word.
  2212. X*/
  2213. X/*ARGSUSED*/
  2214. void
  2215. forward_word(ch)
  2216. X    char ch;
  2217. X{
  2218. X    if (length > 0)
  2219. X    {
  2220. X    /* first skip any delimiters */
  2221. X
  2222. X    for (; (point < length) && (delimit[line[point]]); point++)
  2223. X    {
  2224. X        echo(line[point]);
  2225. X    }
  2226. X
  2227. X    /* now skip until we find a delimiter */
  2228. X
  2229. X    for (; (point < length) && (!delimit[line[point]]); point++)
  2230. X    {
  2231. X        echo(line[point]);
  2232. X    }
  2233. X    }
  2234. X
  2235. X}
  2236. X/*------------------------------------------------------------------*/
  2237. X/*
  2238. Lower case the word.
  2239. X*/
  2240. X/*ARGSUSED*/
  2241. void
  2242. lower_word(ch)
  2243. X    char ch;
  2244. X{
  2245. X    if (length > 0)
  2246. X    {
  2247. X    /* first skip any delimiters */
  2248. X
  2249. X    for (; (point < length) && (delimit[line[point]]); point++)
  2250. X    {
  2251. X        echo(line[point]);
  2252. X    }
  2253. X
  2254. X    /* now skip until we find a delimiter */
  2255. X
  2256. X    for (; (point < length) && (!delimit[line[point]]); point++)
  2257. X    {
  2258. X        if ((line[point] >= 'A') && (line[point] <= 'Z'))
  2259. X        {
  2260. X        line[point] = line[point] - 'A' + 'a';
  2261. X        echo(line[point]);
  2262. X        }
  2263. X        else
  2264. X        {
  2265. X        echo(line[point]);
  2266. X        }
  2267. X    }
  2268. X    }
  2269. X
  2270. X}
  2271. X/*------------------------------------------------------------------*/
  2272. X/*
  2273. Upper case the word.
  2274. X*/
  2275. X/*ARGSUSED*/
  2276. void
  2277. upper_word(ch)
  2278. X    char ch;
  2279. X{
  2280. X    if (length > 0)
  2281. X    {
  2282. X    /* first skip any delimiters */
  2283. X
  2284. X    for (; (point < length) && (delimit[line[point]]); point++)
  2285. X    {
  2286. X        echo(line[point]);
  2287. X    }
  2288. X
  2289. X    /* now skip until we find a delimiter */
  2290. X
  2291. X    for (; (point < length) && (!delimit[line[point]]); point++)
  2292. X    {
  2293. X        if ((line[point] >= 'a') && (line[point] <= 'z'))
  2294. X        {
  2295. X        line[point] = line[point] - 'a' + 'A';
  2296. X        echo(line[point]);
  2297. X        }
  2298. X        else
  2299. X        {
  2300. X        echo(line[point]);
  2301. X        }
  2302. X    }
  2303. X    }
  2304. X
  2305. X}
  2306. X/*------------------------------------------------------------------*/
  2307. X/*
  2308. Capitalize the word.
  2309. X*/
  2310. X/*ARGSUSED*/
  2311. void
  2312. capitalize_word(ch)
  2313. X    char ch;
  2314. X{
  2315. X    if (length > 0)
  2316. X    {
  2317. X    /* first skip any delimiters */
  2318. X
  2319. X    for (; (point < length) && (delimit[line[point]]); point++)
  2320. X    {
  2321. X        echo(line[point]);
  2322. X    }
  2323. X
  2324. X    /* now skip until we find a delimiter */
  2325. X
  2326. X    if ((point < length) && (!delimit[line[point]]))
  2327. X    {
  2328. X        if ((line[point] >= 'a') && (line[point] <= 'z'))
  2329. X        {
  2330. X        line[point] = line[point] - 'a' + 'A';
  2331. X        echo(line[point]);
  2332. X        }
  2333. X        else
  2334. X        {
  2335. X        echo(line[point]);
  2336. X        }
  2337. X    }
  2338. X    point++;
  2339. X
  2340. X    for (; (point < length) && (!delimit[line[point]]); point++)
  2341. X    {
  2342. X        if ((line[point] >= 'A') && (line[point] <= 'Z'))
  2343. X        {
  2344. X        line[point] = line[point] - 'A' + 'a';
  2345. X        echo(line[point]);
  2346. X        }
  2347. X        else
  2348. X        {
  2349. X        echo(line[point]);
  2350. X        }
  2351. X    }
  2352. X    }
  2353. X
  2354. X}
  2355. X/*------------------------------------------------------------------*/
  2356. X/*
  2357. Go backward one word.
  2358. X*/
  2359. X/*ARGSUSED*/
  2360. void
  2361. backward_word(ch)
  2362. X    char ch;
  2363. X{
  2364. X    if (length > 0)
  2365. X    {
  2366. X    /* first backspace over any delimiters */
  2367. X
  2368. X    for (; (point > 0) && (delimit[line[point - 1]]); point--)
  2369. X    {
  2370. X        backspace(line[point - 1]);
  2371. X    }
  2372. X
  2373. X    /* now backspace until we find a delimiter */
  2374. X
  2375. X    for (; (point > 0) && (!delimit[line[point - 1]]); point--)
  2376. X    {
  2377. X        backspace(line[point - 1]);
  2378. X    }
  2379. X    }
  2380. X
  2381. X}
  2382. X/*------------------------------------------------------------------*/
  2383. X/*
  2384. Move the cursor to the start of the line.
  2385. X*/
  2386. X/*ARGSUSED*/
  2387. void
  2388. start_of_line(ch)
  2389. X    char ch;
  2390. X{
  2391. X    int i;
  2392. X
  2393. X    if (length > 0)
  2394. X    {
  2395. X    for (i = 0; i < point; i++)
  2396. X    {
  2397. X        backspace(line[i]);
  2398. X    }
  2399. X    point = 0;
  2400. X    }
  2401. X}
  2402. X/*------------------------------------------------------------------*/
  2403. X/*
  2404. Move the cursor one character to the left.
  2405. X*/
  2406. X/*ARGSUSED*/
  2407. void
  2408. backward_char(ch)
  2409. X    char ch;
  2410. X{
  2411. X    if ((length > 0) && (point > 0))
  2412. X    {
  2413. X    backspace(line[point - 1]);
  2414. X    point--;
  2415. X    }
  2416. X}
  2417. X/*------------------------------------------------------------------*/
  2418. X/*
  2419. Move the cursor to the right of the last character on the line.
  2420. X*/
  2421. X/*ARGSUSED*/
  2422. void
  2423. end_of_line(ch)
  2424. X    char ch;
  2425. X{
  2426. X    if ((length > 0) && (point < length))
  2427. X    {
  2428. X    echoline(&line[point], (length - point));
  2429. X    point = length;
  2430. X    }
  2431. X}
  2432. X/*------------------------------------------------------------------*/
  2433. X/*
  2434. Move the cursor one character to the right.
  2435. X*/
  2436. X/*ARGSUSED*/
  2437. void
  2438. forward_char(ch)
  2439. X    char ch;
  2440. X{
  2441. X    if ((length > 0) && (point < length))
  2442. X    {
  2443. X    echo(line[point]);
  2444. X    point++;
  2445. X    }
  2446. X}
  2447. X/*------------------------------------------------------------------*/
  2448. X/*
  2449. Add a line to the history buffer and pass it to the child process
  2450. as input.
  2451. X*/
  2452. X/*ARGSUSED*/
  2453. void
  2454. add_to_history(ch)
  2455. X    char ch;
  2456. X{
  2457. X    /* Put the line in the history buffer. Make here point to the current
  2458. X     * line. And increment head to point to the next history slot. */
  2459. X
  2460. X    /* If the current line is identical to the current history line, don't
  2461. X     * add it. */
  2462. X
  2463. X    /* don't save blank lines */
  2464. X
  2465. X    int prev;
  2466. X
  2467. X    if ((head - 1) < 0)
  2468. X    {
  2469. X    prev = HISTORY_SIZE - 1;
  2470. X    }
  2471. X    else
  2472. X    {
  2473. X    prev = head - 1;
  2474. X    }
  2475. X
  2476. X    if ((length != 0) &&
  2477. X    ((length != hist[prev].length) ||
  2478. X        (strncmp(hist[prev].line, line, length) != 0)))
  2479. X    {
  2480. X    /* set the length of the entry */
  2481. X
  2482. X    hist[head].length = length;
  2483. X
  2484. X    /* make sure there is enough storage for the new line */
  2485. X
  2486. X    if (hist[head].line == NULL)
  2487. X    {
  2488. X        if ((hist[head].line = (char *) malloc((unsigned) length)) == NULL)
  2489. X        {
  2490. X        perror("ile");
  2491. X        }
  2492. X    }
  2493. X    else
  2494. X    {
  2495. X        if ((hist[head].line =
  2496. X            (char *) realloc(hist[head].line, (unsigned) length))
  2497. X        == NULL)
  2498. X        {
  2499. X        perror("ile");
  2500. X        }
  2501. X    }
  2502. X
  2503. X    (void) strncpy(hist[head].line, line, length);
  2504. X
  2505. X    head = (head + 1) % HISTORY_SIZE;
  2506. X
  2507. X    if (hist[head].line != NULL)
  2508. X    {
  2509. X        free(hist[head].line);
  2510. X        hist[head].length = 0;
  2511. X        hist[head].line = NULL;
  2512. X    }
  2513. X    }
  2514. X
  2515. X    /* reset here */
  2516. X
  2517. X    here = head;
  2518. X
  2519. X    /* Echo a carriage return or a newline as a cr-nl sequence. Then send the
  2520. X     * line to the child process. Finally, clear the buffer for reuse. */
  2521. X
  2522. X    fputs(ccr, stdout);
  2523. X    fputs(cnl, stdout);
  2524. X
  2525. X    line[length] = nl;
  2526. X    length++;
  2527. X
  2528. X    write_line(line, length);
  2529. X
  2530. X    point = 0;
  2531. X    length = 0;
  2532. X
  2533. X}
  2534. X/*------------------------------------------------------------------*/
  2535. X/*
  2536. XErase the entire line.
  2537. X*/
  2538. X/*ARGSUSED*/
  2539. void
  2540. erase_line(ch)
  2541. X    char ch;
  2542. X{
  2543. X    /* remove any text from the display */
  2544. X
  2545. X    clearline(ch);
  2546. X
  2547. X    /* nothing in the line buffer */
  2548. X
  2549. X    point = 0;
  2550. X    length = 0;
  2551. X
  2552. X    /* reset here */
  2553. X
  2554. X    here = head;
  2555. X
  2556. X}
  2557. X/*------------------------------------------------------------------*/
  2558. X/*
  2559. XErase from the current cursor position to the end of the line.
  2560. X*/
  2561. X/*ARGSUSED*/
  2562. void
  2563. erase_to_end_of_line(ch)
  2564. X    char ch;
  2565. X{
  2566. X    if ((length > 0) && (point < length))
  2567. X    {
  2568. X    cleartoend();
  2569. X    length = point;
  2570. X    }
  2571. X
  2572. X}
  2573. X/*------------------------------------------------------------------*/
  2574. X/*
  2575. Retype the current contents of the edit buffer.
  2576. X*/
  2577. X/*ARGSUSED*/
  2578. void
  2579. retype_line(ch)
  2580. X    char ch;
  2581. X{
  2582. X    int i;
  2583. X
  2584. X    fputs(ccr, stdout);
  2585. X    fputs(cnl, stdout);
  2586. X
  2587. X    echoline(line, length);
  2588. X
  2589. X    for (i = point; i < length; i++)
  2590. X    {
  2591. X    backspace(line[i]);
  2592. X    }
  2593. X}
  2594. X/*------------------------------------------------------------------*/
  2595. X/*
  2596. Go to the the next entry in the history buffer and display it.
  2597. If we are past the last history entry, then beep.
  2598. X*/
  2599. void
  2600. forward_history(ch)
  2601. X    char ch;
  2602. X{
  2603. X    if (here != head)
  2604. X    {
  2605. X    clearline(ch);
  2606. X
  2607. X    here = (here + 1) % HISTORY_SIZE;
  2608. X    length = hist[here].length;
  2609. X    point = length;
  2610. X
  2611. X    (void) strncpy(line, hist[here].line, length);
  2612. X    echoline(line, length);
  2613. X    }
  2614. X    else
  2615. X    {
  2616. X    bell('\0');
  2617. X    }
  2618. X}
  2619. X/*------------------------------------------------------------------*/
  2620. X/*
  2621. Search backward in the history list for a line that starts with
  2622. the characters left of the cursor. If it is found make it the
  2623. current line.
  2624. X*/
  2625. void
  2626. search_backward_history(ch)
  2627. X    char ch;
  2628. X{
  2629. X    int prev;
  2630. X    int i;
  2631. X
  2632. X    /* search backward in the history */
  2633. X
  2634. X    prev = here;
  2635. X
  2636. X    do
  2637. X    {
  2638. X    prev--;
  2639. X
  2640. X    if (prev < 0)
  2641. X    {
  2642. X        prev = HISTORY_SIZE - 1;
  2643. X    }
  2644. X    }
  2645. X    while ((hist[prev].line != NULL) &&
  2646. X    (strncmp(line, hist[prev].line, point) != 0));
  2647. X
  2648. X    /* if something was found, make it the current line */
  2649. X
  2650. X    if (hist[prev].line != NULL)
  2651. X    {
  2652. X    /* remember the position in the history */
  2653. X
  2654. X    here = prev;
  2655. X
  2656. X    /* set the length and point correctly */
  2657. X
  2658. X    length = hist[here].length;
  2659. X    if (point > length)
  2660. X    {
  2661. X        point = length;
  2662. X    }
  2663. X
  2664. X    /* redraw the line */
  2665. X
  2666. X    clearline(ch);
  2667. X    (void) strncpy(line, hist[here].line, hist[here].length);
  2668. X    echoline(line, length);
  2669. X
  2670. X    for (i = point; i < length; i++)
  2671. X    {
  2672. X        backspace(line[i]);
  2673. X    }
  2674. X    }
  2675. X    else
  2676. X    {
  2677. X    bell('\0');
  2678. X    }
  2679. X}
  2680. X/*------------------------------------------------------------------*/
  2681. X/*
  2682. Go back one entry in the history buffer and display it. If we are
  2683. already at the last entry, then beep.
  2684. X*/
  2685. void
  2686. backward_history(ch)
  2687. X    char ch;
  2688. X{
  2689. X    int prev;
  2690. X
  2691. X    prev = here - 1;
  2692. X
  2693. X    if (prev < 0)
  2694. X    {
  2695. X    prev = HISTORY_SIZE - 1;
  2696. X    }
  2697. X
  2698. X    if (hist[prev].line != NULL)
  2699. X    {
  2700. X    clearline(ch);
  2701. X
  2702. X    here = prev;
  2703. X    length = hist[here].length;
  2704. X    point = length;
  2705. X
  2706. X    (void) strncpy(line, hist[here].line, length);
  2707. X    echoline(line, length);
  2708. X    }
  2709. X    else
  2710. X    {
  2711. X    bell('\0');
  2712. X    }
  2713. X}
  2714. X/*------------------------------------------------------------------*/
  2715. X/*
  2716. The following routines are utility routines used by the editing
  2717. routines.
  2718. X*/
  2719. X/*------------------------------------------------------------------*/
  2720. X/*
  2721. Clear to the end of the current input line.
  2722. X*/
  2723. void
  2724. cleartoend()
  2725. X{
  2726. X    /* send the clear character */
  2727. X
  2728. X    fputs(cce, stdout);
  2729. X
  2730. X    /* send somes nulls for padding */
  2731. X
  2732. X    fputs("\0\0\0\0", stdout);
  2733. X}
  2734. X/*------------------------------------------------------------------*/
  2735. X/*
  2736. Clear the input line. Backspace to the start of the line. Then clear
  2737. to the end of the line.
  2738. X*/
  2739. X/*ARGSUSED*/
  2740. void
  2741. clearline(ch)
  2742. X    char ch;
  2743. X{
  2744. X    int i;
  2745. X
  2746. X    for (i = 0; i < point; i++)
  2747. X    {
  2748. X    backspace(line[i]);
  2749. X    }
  2750. X
  2751. X    cleartoend();
  2752. X}
  2753. X/*------------------------------------------------------------------*/
  2754. X/*
  2755. XEcho a character. Not all characters are created equal. Control characters
  2756. are echoed in ^X form. So they take up two character positions instead of
  2757. the normal 1 character position.
  2758. X*/
  2759. void
  2760. echo(ch)
  2761. X    char ch;
  2762. X{
  2763. X    /* how should we echo the char? */
  2764. X
  2765. X    if (ch < ' ')
  2766. X    {
  2767. X    (void) fputc('^', stdout);
  2768. X    (void) fputc('@' + ch, stdout);
  2769. X    }
  2770. X    else
  2771. X    {
  2772. X    (void) fputc(ch, stdout);
  2773. X    }
  2774. X}
  2775. X/*------------------------------------------------------------------*/
  2776. X/*
  2777. XEcho a line. Print a whole line with control characters printed in
  2778. X^X form.
  2779. X*/
  2780. void
  2781. echoline(line, length)
  2782. X    char *line;
  2783. X    int length;
  2784. X{
  2785. X    int i;
  2786. X
  2787. X    for (i = 0; i < length; i++)
  2788. X    {
  2789. X    echo(*line++);
  2790. X    }
  2791. X
  2792. X}
  2793. X/*------------------------------------------------------------------*/
  2794. X/*
  2795. Backspace over a character. Generate enough bs characters to backspace
  2796. over any character.
  2797. X*/
  2798. void
  2799. backspace(ch)
  2800. X    char ch;
  2801. X{
  2802. X    if (ch < ' ')
  2803. X    {
  2804. X    fputs(cle, stdout);
  2805. X    fputs(cle, stdout);
  2806. X    }
  2807. X    else
  2808. X    {
  2809. X    fputs(cle, stdout);
  2810. X    }
  2811. X}
  2812. X/*------------------------------------------------------------------*/
  2813. X/*
  2814. Add any character to the line buffer.
  2815. X*/
  2816. void
  2817. quote_edit(ch)
  2818. X    char ch;
  2819. X{
  2820. X    insert(ch);
  2821. X
  2822. X    edit = edit_0;
  2823. X}
  2824. X/*------------------------------------------------------------------*/
  2825. X/*
  2826. Given a character and an action table number either execute the
  2827. action or pass the string to (*edit)(ch)
  2828. X*/
  2829. void
  2830. dispatch(table, ch)
  2831. X    int table;
  2832. X    char ch;
  2833. X{
  2834. X    char *cptr;
  2835. X
  2836. X    switch (action_table[table][ch].flag)
  2837. X    {
  2838. X    case is_action:
  2839. X
  2840. X    (*(action_table[table][ch].aors.action)) (ch);
  2841. X
  2842. X    break;
  2843. X
  2844. X    case is_string:
  2845. X
  2846. X    cptr = action_table[table][ch].aors.string;
  2847. X    while ((*cptr) != '\0')
  2848. X    {
  2849. X        (*edit) (*cptr);
  2850. X        cptr++;
  2851. X    }
  2852. X
  2853. X    break;
  2854. X    }
  2855. X}
  2856. X/*------------------------------------------------------------------*/
  2857. X/*
  2858. Select an action from action_table[3] and execute it.
  2859. X*/
  2860. void
  2861. edit_3(ch)
  2862. X    char ch;
  2863. X{
  2864. X    /* reset so that next input is handled by edit_0 unless over ridden by
  2865. X     * the action. */
  2866. X
  2867. X    edit = edit_0;
  2868. X    dispatch(3, ch);
  2869. X    (void) fflush(stdout);
  2870. X}
  2871. X/*------------------------------------------------------------------*/
  2872. X/*
  2873. Select an action from action_table[2] and execute it.
  2874. X*/
  2875. void
  2876. edit_2(ch)
  2877. X    char ch;
  2878. X{
  2879. X    /* reset so that next input is handled by edit_0 unless over ridden by
  2880. X     * the action. */
  2881. X
  2882. X    edit = edit_0;
  2883. X    dispatch(2, ch);
  2884. X    (void) fflush(stdout);
  2885. X}
  2886. X/*------------------------------------------------------------------*/
  2887. X/*
  2888. Select an action from action_table[1] and execute it.
  2889. X*/
  2890. void
  2891. edit_1(ch)
  2892. X    char ch;
  2893. X{
  2894. X    /* reset so that next input is handled by edit_0 unless over ridden by
  2895. X     * the action. */
  2896. X
  2897. X    edit = edit_0;
  2898. X    dispatch(1, ch);
  2899. X    (void) fflush(stdout);
  2900. X}
  2901. X/*------------------------------------------------------------------*/
  2902. X/*
  2903. Select an action from action_table[0] and execute it.
  2904. X*/
  2905. void
  2906. edit_0(ch)
  2907. X    char ch;
  2908. X{
  2909. X    dispatch(0, ch);
  2910. X    (void) fflush(stdout);
  2911. X}
  2912. X/*------------------------------------------------------------------*/
  2913. X/*
  2914. Input line editor.
  2915. X
  2916. Initialize the world. Then loop forever using select to wait for
  2917. characters to be available from either stdin or from master_pty.
  2918. When characters are available, pass them on after doing any needed
  2919. editing.
  2920. X*/
  2921. void
  2922. ile()
  2923. X{
  2924. X    /* general purpose integer variable */
  2925. X
  2926. X    int i;
  2927. X
  2928. X    /* arguments for read and write calls */
  2929. X
  2930. X    char buffer[BUFFER_SIZE];
  2931. X    int cc;
  2932. X
  2933. X    /* current slave_tty parameters */
  2934. X
  2935. X    struct sgttyb slave_params;
  2936. X
  2937. X    /* Arguments for select call */
  2938. X
  2939. X    int nfds;
  2940. X    int width;
  2941. X    int readfds;
  2942. X
  2943. X    /* what to do if the child or parent dies */
  2944. X
  2945. X    (void) signal(SIGCHLD, clean_up);
  2946. X    (void) signal(SIGSEGV, clean_up);
  2947. X    (void) signal(SIGBUS, clean_up);
  2948. X    (void) signal(SIGTERM, clean_up);
  2949. X    (void) signal(SIGHUP, clean_up);
  2950. X    (void) signal(SIGINT, clean_up);
  2951. X    (void) signal(SIGQUIT, clean_up);
  2952. X
  2953. X    /* what to do it the window changes size */
  2954. X
  2955. X    (void) signal(SIGWINCH, change_window);
  2956. X
  2957. X    /* Get all the different pieces of the current ttys' state and copy them
  2958. X     * to the slave_tty. */
  2959. X
  2960. X    /* tty sgttyb */
  2961. X
  2962. X    (void) ioctl(READ, TIOCGETP, &tty_sgttyb);
  2963. X    (void) ioctl(slave_tty, TIOCSETP, &tty_sgttyb);
  2964. X
  2965. X    /* tty line discipline */
  2966. X
  2967. X    (void) ioctl(READ, TIOCGETD, &tty_ldisc);
  2968. X    (void) ioctl(slave_tty, TIOCSETD, &tty_ldisc);
  2969. X
  2970. X    /* tty tchars */
  2971. X
  2972. X    (void) ioctl(READ, TIOCGETC, &tty_tchars);
  2973. X    (void) ioctl(slave_tty, TIOCSETC, &tty_tchars);
  2974. X
  2975. X    /* tty mode */
  2976. X
  2977. X    (void) ioctl(READ, TIOCLGET, &tty_mode);
  2978. X    (void) ioctl(slave_tty, TIOCLSET, &tty_mode);
  2979. X
  2980. X    /* tty ltchars */
  2981. X
  2982. X    (void) ioctl(READ, TIOCGLTC, &tty_ltchars);
  2983. X    (void) ioctl(slave_tty, TIOCSLTC, &tty_ltchars);
  2984. X
  2985. X    /* tty windsize */
  2986. X
  2987. X    (void) ioctl(READ, TIOCGWINSZ, &tty_winsize);
  2988. X    (void) ioctl(slave_tty, TIOCSWINSZ, &tty_winsize);
  2989. X    windowchanged = FALSE;
  2990. X
  2991. X    /* "login" the user */
  2992. X
  2993. X    (void) setutmp(slave_tty, TRUE);
  2994. X
  2995. X    /* set raw mode on tty */
  2996. X    {
  2997. X    struct sgttyb params;
  2998. X    struct tchars tparams;
  2999. X    struct ltchars ltparams;
  3000. X
  3001. X    /* Simulate RAW but allow original parity to work.  Thus we use
  3002. X     * CBREAK with all the options turned off. */
  3003. X
  3004. X    params = tty_sgttyb;
  3005. X    params.sg_flags = CBREAK;
  3006. X    (void) ioctl(READ, TIOCSETP, ¶ms);
  3007. X
  3008. X    tparams = tty_tchars;
  3009. X    tparams.t_intrc = -1;
  3010. X    tparams.t_quitc = -1;
  3011. X    tparams.t_startc = -1;
  3012. X    tparams.t_stopc = -1;
  3013. X    tparams.t_eofc = -1;
  3014. X    tparams.t_brkc = -1;
  3015. X    (void) ioctl(READ, TIOCSETC, &tparams);
  3016. X
  3017. X    ltparams = tty_ltchars;
  3018. X    ltparams.t_suspc = -1;
  3019. X    ltparams.t_dsuspc = -1;
  3020. X    ltparams.t_rprntc = -1;
  3021. X    ltparams.t_flushc = -1;
  3022. X    ltparams.t_lnextc = -1;
  3023. X    (void) ioctl(READ, TIOCSLTC, <params);
  3024. X    }
  3025. X
  3026. X    /* set new mode on tty */
  3027. X
  3028. X    {
  3029. X    int mode;
  3030. X    mode = LNOFLSH | LDECCTQ | LLITOUT;
  3031. X    (void) ioctl(READ, TIOCLSET, &mode);
  3032. X    }
  3033. X
  3034. X    /* get descriptor table size */
  3035. X
  3036. X    width = getdtablesize();
  3037. X    if (width > 32)
  3038. X    {
  3039. X    width = 32;
  3040. X    }
  3041. X
  3042. X    /* set initial edit function */
  3043. X
  3044. X    edit = edit_0;
  3045. X
  3046. X    /* initialize line buffer */
  3047. X
  3048. X    point = 0;
  3049. X    length = 0;
  3050. X
  3051. X    /* initialize history buffer */
  3052. X
  3053. X    head = 0;
  3054. X    here = 0;
  3055. X
  3056. X    for (i = 0; i < HISTORY_SIZE; i++)
  3057. X    {
  3058. X    hist[i].length = 0;
  3059. X    hist[i].line = NULL;
  3060. X    }
  3061. X
  3062. X    for (;;)
  3063. X    {
  3064. X    readfds = (1 << READ) | (1 << master_pty);
  3065. X
  3066. X    /* wait for input from stdin or master_pty */
  3067. X
  3068. X    nfds = select(width,
  3069. X        (fd_set *) & readfds,
  3070. X        (fd_set *) NULL,
  3071. X        (fd_set *) NULL,
  3072. X        (struct timeval *) NULL);
  3073. X
  3074. X    if (nfds == -1)        /* an exception has occured */
  3075. X    {
  3076. X        if (windowchanged)
  3077. X        {
  3078. X        /* nothing serious, the window changed size */
  3079. X
  3080. X        windowchanged = FALSE;
  3081. X        }
  3082. X        else
  3083. X        {
  3084. X        perror("ile");
  3085. X        clean_up();
  3086. X        }
  3087. X    }
  3088. X    else if ((nfds > 0) && (readfds != 0))    /* something to read */
  3089. X    {
  3090. X        if ((readfds & (1 << master_pty)) != 0)
  3091. X        {
  3092. X        /* read the pending characters. */
  3093. X
  3094. X        cc = read(master_pty, buffer, BUFFER_SIZE);
  3095. X
  3096. X        /* display the characters. */
  3097. X
  3098. X        (void) write(WRITE, buffer, cc);
  3099. X        }
  3100. X
  3101. X        if ((readfds & (1 << READ)) != 0)
  3102. X        {
  3103. X        /* read the pending characters. */
  3104. X
  3105. X        cc = read(READ, buffer, BUFFER_SIZE);
  3106. X
  3107. X        /* if the slave is in RAW or CBREAK mode, or has turned off
  3108. X         * ECHO then we should not mess with its input characters */
  3109. X
  3110. X        (void) ioctl(slave_tty, TIOCGETP, &slave_params);
  3111. X
  3112. X        if (((slave_params.sg_flags & (RAW | CBREAK)) != 0) ||
  3113. X            (slave_params.sg_flags & ECHO) == 0)
  3114. X        {
  3115. X            edit = pass;
  3116. X        }
  3117. X        else if (edit == (void (*) ()) pass)
  3118. X        {
  3119. X            edit = edit_0;
  3120. X        }
  3121. X
  3122. X        /* decide what to do with the characters. */
  3123. X
  3124. X        for (i = 0; i < cc; i++)
  3125. X        {
  3126. X            (*edit) (CHAR_MASK & buffer[i]);
  3127. X        }
  3128. X        }
  3129. X
  3130. X    }
  3131. X    }
  3132. X
  3133. X}
  3134. X/*------------------------------------------------------------------*/
  3135. X/*
  3136. The child process.
  3137. X
  3138. Make the pty the processes controling terminal. Bind the pty to
  3139. stdin, stdout, and stderr. Then exec the users program.
  3140. X*/
  3141. void
  3142. child(argv)
  3143. X    char *argv[];
  3144. X{
  3145. X    /* shell name pointers */
  3146. X
  3147. X    char *shellname;
  3148. X    char *shellpath;
  3149. X    char *dashshellname;
  3150. X
  3151. X    /* close all file descriptors */
  3152. X
  3153. X    (void) close(READ);
  3154. X    (void) close(WRITE);
  3155. X    (void) close(ERROR);
  3156. X    (void) close(slave_tty);
  3157. X
  3158. X    /* get rid of controlling terminal */
  3159. X
  3160. X    {
  3161. X    int tty;
  3162. X
  3163. X    if ((tty = open("/dev/tty", O_RDWR) == -1) ||
  3164. X        (ioctl(0, TIOCNOTTY, 0) == -1) ||
  3165. X        (close(tty) == -1))
  3166. X    {
  3167. X        perror("ile");
  3168. X    }
  3169. X    }
  3170. X
  3171. X    /* open the tty again */
  3172. X    /* this makes the pty the controlling terminal */
  3173. X
  3174. X    if ((slave_tty = open(ttydev, O_RDWR)) == -1)
  3175. X    {
  3176. X    perror("ile");
  3177. X    }
  3178. X
  3179. X    /* slave_tty is now stdin */
  3180. X
  3181. X    /* bind slave_tty to stdout */
  3182. X
  3183. X    (void) dup2(slave_tty, WRITE);
  3184. X
  3185. X    /* bind slave_tty to stderr */
  3186. X
  3187. X    (void) dup2(slave_tty, ERROR);
  3188. X
  3189. X    /* close master_pty descriptor */
  3190. X
  3191. X    (void) close(master_pty);
  3192. X
  3193. X    /* Fire up application program. If no program name is given then fire up
  3194. X     * users favorite shell. */
  3195. X
  3196. X    /* get the name of the users shell. default to /bin/csh */
  3197. X
  3198. X    if ((shellpath = getenv("SHELL")) == NULL ||
  3199. X    (*shellpath == '\0'))
  3200. X    {
  3201. X    shellpath = "/bin/csh";
  3202. X    }
  3203. X
  3204. X    /* get just the name */
  3205. X
  3206. X    if ((shellname = strrchr(shellpath, '/')) != NULL)
  3207. X    {
  3208. X    shellname += sizeof(char);
  3209. X    }
  3210. X
  3211. X    /* if the current argv[0] starts with -, then the new argv[0] */
  3212. X    /* should start with - */
  3213. X
  3214. X    if (*(argv[0]) == '-')
  3215. X    {
  3216. X    dashshellname = (char *) malloc((unsigned) strlen(shellname) + 2);
  3217. X    (void) strcpy(dashshellname, "-");
  3218. X    (void) strcat(dashshellname, shellpath);
  3219. X    }
  3220. X    else
  3221. X    {
  3222. X    dashshellname = shellname;
  3223. X    }
  3224. X
  3225. X    /* execute the shell or the specified program */
  3226. X
  3227. X    if (argv[1] == NULL)
  3228. X    {
  3229. X    /* execute default shell */
  3230. X
  3231. X    execlp(shellpath, dashshellname, 0);
  3232. X    }
  3233. X    else if (*argv[1] == '-')
  3234. X    {
  3235. X    /* there is an initialization file */
  3236. X
  3237. X    if (argv[2] == NULL)
  3238. X    {
  3239. X        /* execute default shell */
  3240. X
  3241. X        execlp(shellpath, dashshellname, 0);
  3242. X    }
  3243. X    else
  3244. X    {
  3245. X        /* execute specified program */
  3246. X
  3247. X        execvp(argv[2], &argv[2]);
  3248. X    }
  3249. X    }
  3250. X    else
  3251. X    {
  3252. X    /* execute specified program */
  3253. X
  3254. X    execvp(argv[1], &argv[1]);
  3255. X    }
  3256. X
  3257. X    /* this executes if exec fails */
  3258. X
  3259. X    perror("ile");
  3260. X    exit(1);
  3261. X    /* NOTREACHED */
  3262. X}
  3263. X/*------------------------------------------------------------------*/
  3264. X/*
  3265. Set up default key bindings and delimeters.
  3266. X*/
  3267. void
  3268. default_bindings()
  3269. X{
  3270. X    int i;
  3271. X
  3272. X    /* clear delimiter vector and the action table */
  3273. X
  3274. X    for (i = 0; i < CHAR_SET_SIZE; i++)
  3275. X    {
  3276. X    delimit[i] = FALSE;
  3277. X
  3278. X    action_table[0][i].aors.action = insert;
  3279. X    action_table[1][i].aors.action = bell;
  3280. X    action_table[2][i].aors.action = bell;
  3281. X    action_table[3][i].aors.action = bell;
  3282. X
  3283. X    action_table[0][i].flag = is_action;
  3284. X    action_table[1][i].flag = is_action;
  3285. X    action_table[2][i].flag = is_action;
  3286. X    action_table[3][i].flag = is_action;
  3287. X    }
  3288. X
  3289. X    /* default delimiters */
  3290. X
  3291. X    delimit[' '] = TRUE;    /* blank */
  3292. X    delimit['/'] = TRUE;    /* slash */
  3293. X    delimit['.'] = TRUE;    /* dot */
  3294. X    delimit['-'] = TRUE;    /* dash */
  3295. X
  3296. X    /* default action_table[0] */
  3297. X
  3298. X    action_table[0][CA].aors.action = start_of_line;
  3299. X    action_table[0][CB].aors.action = backward_char;
  3300. X    action_table[0][CE].aors.action = end_of_line;
  3301. X    action_table[0][CF].aors.action = forward_char;
  3302. X    action_table[0][CK].aors.action = erase_to_end_of_line;
  3303. X    action_table[0][CU].aors.action = erase_line;
  3304. X    action_table[0][CL].aors.action = retype_line;
  3305. X    action_table[0][CN].aors.action = forward_history;
  3306. X    action_table[0][CP].aors.action = backward_history;
  3307. X    action_table[0][CR].aors.action = search_backward_history;
  3308. X    action_table[0][CT].aors.action = transpose_chars;
  3309. X    action_table[0][CV].aors.action = quote;
  3310. X    action_table[0][del].aors.action = delete_char;
  3311. X    action_table[0][esc].aors.action = escape_1;
  3312. X    action_table[0][cr].aors.action = add_to_history;
  3313. X    action_table[0][nl].aors.action = add_to_history;
  3314. X    action_table[0][CX].aors.action = delete_char_under;
  3315. X
  3316. X    action_table[0][CC].aors.action = pass;
  3317. X    action_table[0][CD].aors.action = pass;
  3318. X    action_table[0][CQ].aors.action = pass;
  3319. X    action_table[0][CS].aors.action = pass;
  3320. X    action_table[0][CZ].aors.action = pass;
  3321. X
  3322. X    /* default action_table[1] ^[ c */
  3323. X
  3324. X    action_table[1]['b'].aors.action = backward_word;
  3325. X    action_table[1]['f'].aors.action = forward_word;
  3326. X    action_table[1][del].aors.action = delete_word;
  3327. X    action_table[1]['u'].aors.action = upper_word;
  3328. X    action_table[1]['l'].aors.action = lower_word;
  3329. X    action_table[1]['c'].aors.action = capitalize_word;
  3330. X    action_table[1]['['].aors.action = escape_2;
  3331. X    action_table[1][esc].aors.action = complete_file;
  3332. X    action_table[1]['s'].aors.action = complete_file_full;
  3333. X    action_table[1]['d'].aors.action = show_files;
  3334. X    action_table[1]['p'].aors.action = query_path;
  3335. X
  3336. X    /* default action_table[2] ^[ [ */
  3337. X
  3338. X    action_table[2]['A'].aors.action = backward_history;
  3339. X    action_table[2]['B'].aors.action = forward_history;
  3340. X    action_table[2]['C'].aors.action = forward_char;
  3341. X    action_table[2]['D'].aors.action = backward_char;
  3342. X
  3343. X}
  3344. X/*------------------------------------------------------------------*/
  3345. X/*
  3346. Return a character or EOF. This routine reads characters from input
  3347. and converts them into a character using the following rules.
  3348. X
  3349. The character may be a single character, a control
  3350. character indicated by ^x, an octal number starting with \, or an
  3351. escaped character indictated by \x.
  3352. X*/
  3353. int
  3354. scan_char(input)
  3355. X    FILE *input;
  3356. X{
  3357. X    int ch;
  3358. X    int value;
  3359. X
  3360. X    ch = fgetc(input);
  3361. X    switch (ch)
  3362. X    {
  3363. X    case '^':
  3364. X
  3365. X    /* it is a control character */
  3366. X
  3367. X    for (ch = fgetc(input); '@' <= ch; ch = ch - '@');
  3368. X
  3369. X    break;
  3370. X
  3371. X    case '\\':
  3372. X
  3373. X    /* octal or an escaped character? */
  3374. X
  3375. X    ch = fgetc(input);
  3376. X    if (('0' <= ch) && (ch <= '7'))
  3377. X    {
  3378. X
  3379. X        /* its an octal number */
  3380. X
  3381. X        value = 0;
  3382. X        while (('0' <= ch) && (ch <= '7'))
  3383. X        {
  3384. X        value = (value * 8) + (ch - '0');
  3385. X        ch = fgetc(input);
  3386. X        }
  3387. X        (void) ungetc(ch, input);
  3388. X
  3389. X        ch = value & 0177;    /* make sure it is in range */
  3390. X    }
  3391. X    else
  3392. X    {
  3393. X        /* its an escaped character */
  3394. X
  3395. X        ch = fgetc(input);
  3396. X    }
  3397. X
  3398. X    break;
  3399. X
  3400. X    case '\n':
  3401. X
  3402. X    /* the real end of the line */
  3403. X
  3404. X    ch = EOL;
  3405. X
  3406. X    break;
  3407. X
  3408. X    default:
  3409. X
  3410. X    /* it is just itself */
  3411. X
  3412. X    break;
  3413. X    }
  3414. X
  3415. X    return (ch);
  3416. X
  3417. X}
  3418. X/*------------------------------------------------------------------*/
  3419. X/*
  3420. Set key bindings and delimiters from the users file.
  3421. X*/
  3422. void
  3423. user_bindings(file)
  3424. X    FILE *file;
  3425. X{
  3426. X
  3427. X#define NAME_SIZE 40
  3428. X
  3429. X    static struct action_name_table
  3430. X    {
  3431. X    char *name;
  3432. X    void (*action) ();
  3433. X    } action_name_table[] =
  3434. X    {
  3435. X    {
  3436. X        "complete_file_full", complete_file_full
  3437. X    },
  3438. X    {
  3439. X        "complete_file", complete_file
  3440. X    },
  3441. X    {
  3442. X        "show_files", show_files
  3443. X    },
  3444. X    {
  3445. X        "query_path", query_path
  3446. X    },
  3447. X    {
  3448. X        "bell", bell
  3449. X    },
  3450. X    {
  3451. X        "pass", pass
  3452. X    },
  3453. X    {
  3454. X        "insert", insert
  3455. X    },
  3456. X    {
  3457. X        "transpose_chars", transpose_chars
  3458. X    },
  3459. X    {
  3460. X        "delete_char", delete_char
  3461. X    },
  3462. X    {
  3463. X        "delete_char_under", delete_char_under
  3464. X    },
  3465. X    {
  3466. X        "quote", quote
  3467. X    },
  3468. X    {
  3469. X        "escape_1", escape_1
  3470. X    },
  3471. X    {
  3472. X        "escape_2", escape_2
  3473. X    },
  3474. X    {
  3475. X        "escape_3", escape_3
  3476. X    },
  3477. X    {
  3478. X        "delete_word", delete_word
  3479. X    },
  3480. X    {
  3481. X        "upper_word", upper_word
  3482. X    },
  3483. X    {
  3484. X        "lower_word", lower_word
  3485. X    },
  3486. X    {
  3487. X        "capitalize_word", capitalize_word
  3488. X    },
  3489. X    {
  3490. X        "forward_word", forward_word
  3491. X    },
  3492. X    {
  3493. X        "backward_word", backward_word
  3494. X    },
  3495. X    {
  3496. X        "start_of_line", start_of_line
  3497. X    },
  3498. X    {
  3499. X        "backward_char", backward_char
  3500. X    },
  3501. X    {
  3502. X        "end_of_line", end_of_line
  3503. X    },
  3504. X    {
  3505. X        "forward_char", forward_char
  3506. X    },
  3507. X    {
  3508. X        "add_to_history", add_to_history
  3509. X    },
  3510. X    {
  3511. X        "erase_line", erase_line
  3512. X    },
  3513. X    {
  3514. X        "erase_to_end_of_line", erase_to_end_of_line
  3515. X    },
  3516. X    {
  3517. X        "retype_line", retype_line
  3518. X    },
  3519. X    {
  3520. X        "forward_history", forward_history
  3521. X    },
  3522. X    {
  3523. X        "backward_history", backward_history
  3524. X    },
  3525. X    {
  3526. X        "search_backward_history", search_backward_history
  3527. X    },
  3528. X    {
  3529. X        "", NULL
  3530. X    }
  3531. X    };
  3532. X
  3533. X    char name[NAME_SIZE];
  3534. X
  3535. X    int ch;
  3536. X    int i;
  3537. X
  3538. X    int linecount;
  3539. X    int table;
  3540. X    int entry;
  3541. X
  3542. X    /* First clear the default delimiters */
  3543. X
  3544. X    for (i = 0; i < CHAR_SET_SIZE; i++)
  3545. X    {
  3546. X    delimit[i] = FALSE;
  3547. X    }
  3548. X
  3549. X    /* Now read the delimiter characters */
  3550. X
  3551. X    while (((int) (ch = fgetc(file)) != EOF) && (ch != '\n'))
  3552. X    {
  3553. X    delimit[ch] = TRUE;
  3554. X    }
  3555. X
  3556. X    linecount = 2;
  3557. X
  3558. X    /* Now read the character binding pairs */
  3559. X
  3560. X    while ((int) (ch = fgetc(file)) != EOF)
  3561. X    {
  3562. X    switch (ch)
  3563. X    {
  3564. X    case '\n':
  3565. X
  3566. X        /* skipping a blank line */
  3567. X        linecount++;
  3568. X
  3569. X        break;
  3570. X
  3571. X    case '0':
  3572. X    case '1':
  3573. X    case '2':
  3574. X    case '3':
  3575. X
  3576. X        /* which table is this entry directed to? */
  3577. X
  3578. X        table = ch - '0';
  3579. X
  3580. X        /* get the character code */
  3581. X
  3582. X        entry = scan_char(file);
  3583. X
  3584. X        /* make sure the '=' is there */
  3585. X
  3586. X        ch = fgetc(file);
  3587. X        if (ch != '=')
  3588. X        {
  3589. X        (void) fprintf(stderr,
  3590. X            "ile: '=' missing on line %d\n",
  3591. X            linecount);
  3592. X        exit(1);
  3593. X        /* NOTREACHED */
  3594. X        }
  3595. X
  3596. X        /* collect the action name or string */
  3597. X
  3598. X        for (ch = scan_char(file), i = 0;
  3599. X        ((int) ch != EOL) && (i < (NAME_SIZE - 1));
  3600. X        ch = scan_char(file), i++)
  3601. X        {
  3602. X        name[i] = ch;
  3603. X        name[i + 1] = '\0';
  3604. X        }
  3605. X
  3606. X        /* look it up in the action_name_table */
  3607. X
  3608. X        for (i = 0;
  3609. X        (action_name_table[i].action != NULL) &&
  3610. X        (strcmp(name, action_name_table[i].name) != 0);
  3611. X        i++);
  3612. X
  3613. X        /* if it was found, put it in the action array */
  3614. X
  3615. X        if (action_name_table[i].action == NULL)
  3616. X        {
  3617. X        /* must be a string */
  3618. X
  3619. X        action_table[table][entry].flag = is_string;
  3620. X        action_table[table][entry].aors.string =
  3621. X            (char *) malloc((unsigned) strlen(name) + 1);
  3622. X        (void) strcpy(action_table[table][entry].aors.string, name);
  3623. X        }
  3624. X        else
  3625. X        {
  3626. X        /* its an action */
  3627. X
  3628. X        action_table[table][entry].flag = is_action;
  3629. X        action_table[table][entry].aors.action =
  3630. X            action_name_table[i].action;
  3631. X        }
  3632. X
  3633. X        linecount++;    /* count the line */
  3634. X
  3635. X        break;
  3636. X
  3637. X    default:
  3638. X        (void) fprintf(stderr,
  3639. X        "\nile: error in initialization file on line %d\n",
  3640. X        linecount);
  3641. X        exit(1);
  3642. X        /* NOTREACHED */
  3643. X    }
  3644. X    }
  3645. X
  3646. X    (void) fclose(file);
  3647. X}
  3648. X/*------------------------------------------------------------------*/
  3649. X/*
  3650. Initialize key bindings and delimiters.
  3651. X*/
  3652. void
  3653. initialize(argv)
  3654. X    char *argv[];
  3655. X{
  3656. X    FILE *file;
  3657. X    char name[BUFFER_SIZE];
  3658. X    char *pwd;
  3659. X
  3660. X    /* set up the default bindings */
  3661. X
  3662. X    default_bindings();
  3663. X
  3664. X    /* Look for an initialization file. If it's there, load it. */
  3665. X
  3666. X    name[0] = '\0';
  3667. X    homedir = getenv("HOME");
  3668. X    if (homedir == NULL)
  3669. X    {
  3670. X    /* no home dir, use / instead */
  3671. X    name[0] = '\0';
  3672. X    }
  3673. X    else
  3674. X    {
  3675. X    (void) strcpy(name, homedir);
  3676. X    }
  3677. X    (void) strcat(name, "/.ilerc");
  3678. X
  3679. X    /* initialize currentdir */
  3680. X
  3681. X    pwd = getenv("PWD");
  3682. X    if (pwd == NULL)
  3683. X    {
  3684. X    /* no pwd, use homedir instead */
  3685. X    (void) strcpy(currentdir, homedir);
  3686. X    }
  3687. X    else
  3688. X    {
  3689. X    (void) strcpy(currentdir, pwd);
  3690. X    }
  3691. X
  3692. X    if ((argv[1] != NULL) &&
  3693. X    (*argv[1] == '-') &&
  3694. X    ((file = fopen(argv[1] + 1, "r")) != NULL))
  3695. X    {
  3696. X    /* load the users bindings */
  3697. X
  3698. X    user_bindings(file);
  3699. X    }
  3700. X    else if (((file = fopen("./.ilerc", "r")) != NULL) ||
  3701. X    ((file = fopen(name, "r")) != NULL))
  3702. X    {
  3703. X    user_bindings(file);
  3704. X    }
  3705. X}
  3706. X/*------------------------------------------------------------------*/
  3707. X/*
  3708. X*/
  3709. X/*ARGSUSED*/
  3710. main(argc, argv)
  3711. X    int argc;
  3712. X    char *argv[];
  3713. X{
  3714. X
  3715. X    /* Child process id */
  3716. X
  3717. X    int childpid;
  3718. X
  3719. X    /* identify yourself */
  3720. X
  3721. X    (void) fprintf(stdout, "ile rev.2\n\r");
  3722. X
  3723. X    /* create the tty/pty pair */
  3724. X
  3725. X    getpty(&master_pty, &slave_tty);
  3726. X
  3727. X    /* get control sequences from termcap */
  3728. X
  3729. X    get_termcap();
  3730. X
  3731. X    /* initialize the dispatch vectors */
  3732. X
  3733. X    initialize(argv);
  3734. X
  3735. X    /* create the child process */
  3736. X
  3737. X    childpid = fork();
  3738. X
  3739. X    switch (childpid)
  3740. X    {
  3741. X    case 0:            /* child process */
  3742. X
  3743. X    child(argv);
  3744. X    break;
  3745. X
  3746. X    case -1:            /* fork failed */
  3747. X
  3748. X    perror("ile");
  3749. X    exit(1);
  3750. X    /* NOTREACHED */
  3751. X
  3752. X    default:            /* parent process */
  3753. X    ile();
  3754. X    break;
  3755. X    }
  3756. X
  3757. X}
  3758. END_OF_FILE
  3759. if test 60367 -ne `wc -c <'ile.c'`; then
  3760.     echo shar: \"'ile.c'\" unpacked with wrong size!
  3761. fi
  3762. # end of 'ile.c'
  3763. fi
  3764. echo shar: End of archive 1 \(of 1\).
  3765. cp /dev/null ark1isdone
  3766. MISSING=""
  3767. for I in 1 ; do
  3768.     if test ! -f ark${I}isdone ; then
  3769.     MISSING="${MISSING} ${I}"
  3770.     fi
  3771. done
  3772. if test "${MISSING}" = "" ; then
  3773.     echo You have the archive.
  3774.     rm -f ark[1-9]isdone
  3775. else
  3776.     echo You still need to unpack the following archives:
  3777.     echo "        " ${MISSING}
  3778. fi
  3779. ##  End of shell archive.
  3780. exit 0
  3781.